C++使用cjson操作Json格式文件(創(chuàng)建、插入、解析、修改、刪除)
為什么要學(xué)習(xí)解析Json文件?
工作需要唄!
最近在工作項(xiàng)目中,有需求是需要進(jìn)行解析Json字符串的,但是我只會(huì)使用QT去解析Json,且主管規(guī)定要使用C/C++語(yǔ)言去解析,說(shuō)是為了方便移植到其他項(xiàng)目中進(jìn)行使用…
沒(méi)辦法,只能硬著頭皮,在網(wǎng)上找找有沒(méi)有什么解析Json的開(kāi)源庫(kù)是C/C++可以使用的。
找了許多,網(wǎng)上也提供了許多,最終我選擇了cJOSN,不為什么,就是因?yàn)樗∏闪岘嚕沂羌僀的!
花了一兩周的悠閑時(shí)間去學(xué)習(xí),把一些比較常用的解析的JSON字符串解析解析記錄下來(lái)!
最后簡(jiǎn)單介紹一下json是什么吧:
json是一個(gè)輕量級(jí)的數(shù)據(jù)存儲(chǔ)交換語(yǔ)言,其是通過(guò)鍵值對(duì)的形式存儲(chǔ)的,例如:{ “key” : “value” }
注意:鍵需要使用雙引號(hào)括起來(lái),值如果是字符串也需要使用雙引號(hào)括起來(lái),其他類型不需要。
json主要用來(lái)網(wǎng)絡(luò)數(shù)據(jù)傳輸!
一、準(zhǔn)備cJSON開(kāi)源庫(kù)
cjosn庫(kù)下載網(wǎng)址:https://sourceforge.net/projects/cjson/

下載后會(huì)得到一個(gè)壓縮包,解壓后進(jìn)入里面拷貝cJSON.c和cJSON.h文件到自己的項(xiàng)目中去。

最后在自己的項(xiàng)目中把這兩個(gè)文件添加進(jìn)來(lái)即可!
Linux 和 Window下都可以使用!

二、cJSON介紹
首先介紹一下json數(shù)據(jù):

上圖的json數(shù)據(jù)就是這篇博客將要操作的,將會(huì)對(duì)其進(jìn)行創(chuàng)建、解析、修改、刪除操作。
其中這里包含項(xiàng)目中常用的封裝和解析。
cJSON主要是通過(guò)結(jié)構(gòu)體cJSON進(jìn)行存儲(chǔ)數(shù)據(jù):
typedef struct cJSON {
struct cJSON *next,*prev; /* next是獲取下一個(gè)元素?cái)?shù)據(jù),prev是獲取前一個(gè)元素?cái)?shù)據(jù) */
struct cJSON *child; /* 獲取第一個(gè)元素?cái)?shù)據(jù),當(dāng)需要獲取下一個(gè)時(shí),就得使用next了. */
int type; /* 當(dāng)前的json類型對(duì)象、數(shù)組、字符串、數(shù)字、null、true、false等 */
char *valuestring; /* 字符串值, if type==cJSON_String */
int valueint; /* 整形類型值, if type==cJSON_Number */
double valuedouble; /* 浮點(diǎn)數(shù)類型值, if type==cJSON_Number */
char *string; /* 這個(gè)是鍵 */
} cJSON;
type類型,與下面的宏進(jìn)行判斷
/* cJSON Types: */ #define cJSON_False 0 // true #define cJSON_True 1 // false #define cJSON_NULL 2 // NULL #define cJSON_Number 3 // 數(shù)字 #define cJSON_String 4 // 字符串 #define cJSON_Array 5 // 數(shù)組 #define cJSON_Object 6 // 對(duì)象
字符串生成cjson指針的函數(shù),使用后需要調(diào)用cJSON_Delete進(jìn)行釋放
extern cJSON *cJSON_Parse(const char *value); // 釋放cJSON_Parse返回的指針 extern void cJSON_Delete(cJSON *c);
cjson指針指針生成字符串的函數(shù)
// 這個(gè)生成的字符串有做格式調(diào)整 extern char *cJSON_Print(cJSON *item); // 這個(gè)沒(méi)有作格式調(diào)整,就是一行字符串顯示 extern char *cJSON_PrintUnformatted(cJSON *item);
使用這個(gè)兩個(gè)函數(shù)一定一定一定要釋放它們返回的指針內(nèi)存,否則會(huì)造成內(nèi)存泄漏。
…
其他的就不介紹了,都會(huì)在下面中使用到!
三、封裝Json
{ }
"interest": {
"basketball": "籃球",
"badminton": "羽毛球"
}
代碼實(shí)現(xiàn)上述效果:
// 定義對(duì)象 { }
cJSON *interest = cJSON_CreateObject();
// 插入元素,對(duì)應(yīng) 鍵值對(duì)
cJSON_AddItemToObject(interest, "basketball", cJSON_CreateString("籃球")); // 當(dāng)值是字符串時(shí),需要使用函數(shù)cJSON_CreateString()創(chuàng)建
cJSON_AddItemToObject(interest, "badminton", cJSON_CreateString("羽毛球"));
// 或者使用宏進(jìn)行添加
//cJSON_AddStringToObject(interest, "badminton", "羽毛球"); // 或者這樣寫
[ ]
"color": [ "black", "white"]
代碼實(shí)現(xiàn)上述效果:
// 定義 [ ] 數(shù)組
cJSON *color = cJSON_CreateArray();
// 往數(shù)組中添加元素
cJSON_AddItemToArray(color, cJSON_CreateString("black"));
cJSON_AddItemToArray(color, cJSON_CreateString("white"));
[ { }, { } ]
"like": [
{ "game": "馬里奧", "price": 66.6 },
{ "game": "魂斗羅", "price": 77.7 }
]
代碼實(shí)現(xiàn)上述效果:
// 定義 { } 對(duì)象
cJSON *likeObject1 = cJSON_CreateObject();
cJSON_AddItemToObject(likeObject1, "game", cJSON_CreateString("馬里奧"));
cJSON_AddItemToObject(likeObject1, "price", cJSON_CreateNumber(66.6)); // 當(dāng)值是數(shù)字時(shí),需要使用函數(shù)cJSON_CreateNumber()創(chuàng)建
//cJSON_AddNumberToObject(likeObject1, "price", 66.6); // 或者這樣寫
cJSON *likeObject2 = cJSON_CreateObject();
cJSON_AddItemToObject(likeObject2, "game", cJSON_CreateString("魂斗羅"));
cJSON_AddItemToObject(likeObject2, "price", cJSON_CreateNumber(77.7));
// 定義 [ ] 數(shù)組
cJSON *like = cJSON_CreateArray();
// 往數(shù)組中添加元素
cJSON_AddItemToArray(like, likeObject1);
cJSON_AddItemToArray(like, likeObject2);
[ [ ], [ ] ]
"education": [
[ "小學(xué)", "初中" ],
[ "高中", "大學(xué)" ]
]
代碼實(shí)現(xiàn)上述效果:
// 定義 [ ] 數(shù)組
cJSON *education1 = cJSON_CreateArray();
cJSON_AddItemToArray(education1, cJSON_CreateString("小學(xué)"));
cJSON_AddItemToArray(education1, cJSON_CreateString("初中"));
cJSON *education2 = cJSON_CreateArray();
cJSON_AddItemToArray(education2, cJSON_CreateString("高中"));
cJSON_AddItemToArray(education2, cJSON_CreateString("大學(xué)"));
// 定義 [ ] 數(shù)組
cJSON *education = cJSON_CreateArray();
cJSON_AddItemToArray(education, education1);
cJSON_AddItemToArray(education, education2);
{ { }, { } }
"languages": {
"serialOne": { "language": "漢語(yǔ)", "grade": 10 },
"serialTwo": { "language": "英語(yǔ)", "grade": 6}
}
代碼實(shí)現(xiàn)上述效果:
// 定義對(duì)象 { }
cJSON *serialOne = cJSON_CreateObject();
cJSON_AddItemToObject(serialOne, "language", cJSON_CreateString("漢語(yǔ)"));
cJSON_AddItemToObject(serialOne, "grade", cJSON_CreateNumber(10));
cJSON *serialTwo = cJSON_CreateObject();
cJSON_AddItemToObject(serialTwo, "language", cJSON_CreateString("英語(yǔ)"));
cJSON_AddItemToObject(serialTwo, "grade", cJSON_CreateNumber(6));
// 定義對(duì)象 { }
cJSON *languages = cJSON_CreateObject();
cJSON_AddItemToObject(languages, "serialOne", serialOne);
cJSON_AddItemToObject(languages, "serialTwo", serialTwo);
定義根節(jié)點(diǎn) 也即是最外層 { }
// 創(chuàng)建跟對(duì)象 cJSON *root = cJSON_CreateObject();
將上面定義的{ } 與 [ ] 都插入到跟節(jié)點(diǎn){ }中
// 將子項(xiàng)插入根項(xiàng)中
cJSON_AddItemToObject(root, "name", cJSON_CreateString("小明")); // "name": "小明"
cJSON_AddItemToObject(root, "age", cJSON_CreateNumber(23)); // "age": 23
cJSON_AddItemToObject(root, "interest", interest);
cJSON_AddItemToObject(root, "color", color);
cJSON_AddItemToObject(root, "like", like);
cJSON_AddItemToObject(root, "education", education);
cJSON_AddItemToObject(root, "languages", languages);
cJSON_AddItemToObject(root, "vip", cJSON_CreateTrue()); // "vip": true 插入布爾類型數(shù)據(jù)需要使用cJSON_CreateBool函數(shù)
cJSON_AddItemToObject(root, "address", cJSON_CreateNull()); // "address": null 插入NULL值需要使用cJSON_CreateNull函數(shù)
//cJSON_AddTrueToObject(root, "vip");
//cJSON_AddNullToObject(root, "address"); // 或者這樣寫也是可以的
打印控制臺(tái)查看
// 打印控制臺(tái)查看
char *cPrint = cJSON_Print(root);
char *cPrintUnformatted = cJSON_PrintUnformatted(root);
printf("cJSON_Print:\n%s\n", cPrint); // cJSON_Print:有做格式調(diào)整
printf("cJSON_PrintUnformatted:\n%s\n", cPrintUnformatted); // cJSON_PrintUnformatted:沒(méi)有做格式調(diào)整
// 返回的字符串指針需要自己釋放
free(cPrint);
free(cPrintUnformatted);
記得使用cJSON_Print 和 cJSON_PrintUnformatted返回來(lái)的字符指針需要free掉內(nèi)存!

寫入文件中
// 打開(kāi)文件
FILE *file = NULL;
file = fopen(FILE_NAME, "w"); // FILE_NAME ==> "jss.json"
if (file == NULL) {
printf("Open file fail!\n");
// 釋放指針內(nèi)存
cJSON_Delete(root);
return;
}
char *cjValue = cJSON_Print(root);
// 寫入文件
//int ret = fwrite(cjValue, sizeof(char), strlen(cjValue), file);
int ret = fputs(cjValue, file);
if (ret == EOF) {
printf("寫入文件失?。n");
}
fclose(file);
free(cjValue);
釋放掉cJSON指針
// 釋放指針內(nèi)存 cJSON_Delete(root);
把代碼寫好后,編譯運(yùn)行,會(huì)在自己的項(xiàng)目路徑中創(chuàng)建一個(gè)JSON文件,并寫入內(nèi)容,文件內(nèi)容如下:

四、解析Json
解析時(shí)需要使用結(jié)構(gòu)體中的type類型進(jìn)行判斷,這是為了安全性考慮!
解析時(shí)也可以使用cJSON_Print函數(shù)去獲取字符串或者使用結(jié)構(gòu)體中的valuestring進(jìn)行獲取,但是要注意的是,使用cJSON_Print函數(shù)去獲取字符串需要free掉獲取到的指針,否則會(huì)造成內(nèi)存泄漏!
下面解析會(huì)提供兩種方式進(jìn)行解析,第一種是固定的,寫死的方式;第二種是靈活的的方式解析!
打開(kāi)文件讀取josn數(shù)據(jù)
// 打開(kāi)文件
FILE *file = NULL;
file = fopen(FILE_NAME, "r");
if (file == NULL) {
printf("Open file fail!\n");
return;
}
// 獲得文件大小
struct stat statbuf;
stat(FILE_NAME, &statbuf);
int fileSize = statbuf.st_size;
printf("文件大小:%d\n", fileSize);
// 分配符合文件大小的內(nèi)存
char *jsonStr = (char *)malloc(sizeof(char) * fileSize + 1);
memset(jsonStr, 0, fileSize + 1);
// 讀取文件中的json字符串
int size = fread(jsonStr, sizeof(char), fileSize, file);
if (size == 0) {
printf("讀取文件失?。n");
return;
}
printf("%s\n", jsonStr);
fclose(file);
使用讀取到的json數(shù)據(jù)初始化cJSON指針
// 將讀取到的json字符串轉(zhuǎn)換成json變量指針
cJSON *root = cJSON_Parse(jsonStr);
if (!root) {
const char *err = cJSON_GetErrorPtr();
printf("Error before: [%s]\n", err);
free((void *)err);
free(jsonStr);
return;
}
free(jsonStr);
定義一些下面需要使用到的變量
cJSON *item = NULL; char *v_str = NULL; double v_double = 0.0; int v_int = 0; bool v_bool = false;
直接通過(guò)鍵進(jìn)行解析的
// 解析:"name": "小明",
item = cJSON_GetObjectItem(root, "name");
if (item != NULL) {
/* 寫法一:*/
// 判斷是不是字符串類型
//if (item->type == cJSON_String) {
// v_str = cJSON_Print(item); // 通過(guò)函數(shù)獲取值
// printf("name = %s\n", v_str);
// free(v_str); // 通過(guò)函數(shù)返回的指針需要自行free,否則會(huì)導(dǎo)致內(nèi)存泄漏
// v_str = NULL;
//}
/* 寫法二: */
// 判斷是不是字符串類型
if (item->type == cJSON_String) {
v_str = item->valuestring; // 此賦值是淺拷貝,不需要現(xiàn)在釋放內(nèi)存
printf("name = %s\n", v_str);
}
}
// 解析:"age": "23",
item = cJSON_GetObjectItem(root, "age");
if (item != NULL) { // 合法性檢查
if (item->type == cJSON_Number) { // 判斷是不是數(shù)字
v_int = item->valueint; // 獲取值
printf("age = %d\n", v_int);
}
}
// 解析:"vip": true,
item = cJSON_GetObjectItem(root, "vip");
if (item != NULL) {
if (item->type == cJSON_True || item->type == cJSON_False) {
v_str = cJSON_Print(item); // 由于bool類型結(jié)構(gòu)體中沒(méi)有給出,所以使用字符串代替
printf("vip = %s\n", v_str);
free(v_str);
v_str = NULL;
}
}
// 解析:"address": null
item = cJSON_GetObjectItem(root, "address");
if (item != NULL && item->type == cJSON_NULL) {
v_str = cJSON_Print(item); // 由于NULL類型結(jié)構(gòu)體中沒(méi)有給出,所以使用字符串代替
printf("address = %s\n", v_str);
free(v_str);
v_str = NULL;
}
解析對(duì)象 { }
也就是解析下圖內(nèi)容:

解析代碼:
{
/*************** 方式一 ***************/
item = cJSON_GetObjectItem(root, "interest"); // 獲取object對(duì)象名
if (item != NULL) {
cJSON *val = NULL;
val = cJSON_GetObjectItem(item, "basketball"); // 根據(jù)object對(duì)象名獲得里面的basketball數(shù)據(jù)
if (val != NULL && val->type == cJSON_String) {
v_str = val->valuestring;
printf("basketball = %s\n", v_str);
}
val = cJSON_GetObjectItem(item, "badminton"); // 根據(jù)object對(duì)象名獲得里面的badminton數(shù)據(jù)
if (val != NULL && val->type == cJSON_String) {
v_str = val->valuestring;
printf("badminton = %s\n", v_str);
}
}
/*************** 方式二 ***************/
item = cJSON_GetObjectItem(root, "interest");
if (item != NULL) {
cJSON *obj = item->child; // 獲得 "basketball": "籃球"
while (obj) {
if (obj->type == cJSON_String) {
char *v_str = obj->valuestring;
printf("%s = %s\n", obj->string, v_str); // 可以通過(guò)string獲得鍵
}
// 獲取下一個(gè)元素
obj = obj->next;
}
}
}
解析數(shù)組 [ ]
也就是解析下圖內(nèi)容:

解析代碼:
{
/*************** 方式一 ***************/
item = cJSON_GetObjectItem(root, "color");
if (item != NULL) {
int size = cJSON_GetArraySize(item); // 獲得數(shù)組個(gè)數(shù)
for (int i = 0; i < size; i++) {
cJSON *arr = cJSON_GetArrayItem(item, i); // 根據(jù)索引獲得數(shù)組中的值
if (arr != NULL && arr->type == cJSON_String) {
v_str = arr->valuestring;
printf("color = %s\n", v_str);
}
}
}
/*************** 方式二 ***************/
item = cJSON_GetObjectItem(root, "color");
if (item != NULL) {
cJSON *arr = item->child; // 獲得 "black"
while (arr) {
if (arr->type == cJSON_String) {
char *v_str = arr->valuestring;
printf("color = %s\n", v_str);
}
// 獲取下一個(gè)元素
arr = arr->next;
}
}
}
解析數(shù)組中的對(duì)象 [ { } ]
也就是解析下圖內(nèi)容:

解析代碼:
{
/*************** 方式一 ***************/
item = cJSON_GetObjectItem(root, "like");
if (item != NULL) {
int size = cJSON_GetArraySize(item); // 獲取的數(shù)組大小
for (int i = 0; i < size; i++) {
cJSON *obj = cJSON_GetArrayItem(item, i); // 獲取的數(shù)組里的obj
cJSON *val = NULL;
if (obj != NULL && obj->type == cJSON_Object) { // 判斷數(shù)字內(nèi)的元素是不是obj類型
val = cJSON_GetObjectItem(obj, "game"); // 獲得obj里的值
if (val != NULL && val->type == cJSON_String) {
v_str = val->valuestring;
printf("game = %s\n", v_str);
}
val = cJSON_GetObjectItem(obj, "price");
if (val != NULL && val->type == cJSON_Number) {
v_double = val->valuedouble;
printf("price = %.2f\n", v_double);
}
}
}
}
/*************** 方式二 ***************/
item = cJSON_GetObjectItem(root, "like");
if (item != NULL) {
cJSON *obj = item->child; // 獲得 { "game": "馬里奧", "price": 66.6 }
while (obj) {
if (obj->type == cJSON_Object) {
cJSON *objValue = obj->child; // 獲得 "game": "馬里奧"
while (objValue) {
// 再通過(guò)類型去區(qū)分
if (objValue->type == cJSON_String) {
char *v_str = objValue->valuestring;
printf("%s = %s\n", objValue->string, v_str);
} else if (objValue->type == cJSON_Number) {
double v_double = objValue->valuedouble;
printf("%s = %.2f\n", objValue->string, v_double);
}
// 獲取下一個(gè)元素
objValue = objValue->next;
}
}
// 獲取下一組元素
obj = obj->next;
}
}
}
解析 數(shù)組 中 數(shù)組 [ [ ] [ ] ]
也就是解析下圖內(nèi)容:

解析代碼:
{
/*************** 方式一 ***************/
item = cJSON_GetObjectItem(root, "education");
if (item != NULL) {
int size = cJSON_GetArraySize(item); // 獲取的數(shù)組大小
for (int i = 0; i < size; i++) {
cJSON *arr = cJSON_GetArrayItem(item, i); // 解析獲得 [ "小學(xué)", "初中" ]
if (arr != NULL && arr->type == cJSON_Array) {
int arrSize = cJSON_GetArraySize(arr);
for (int j = 0; j < arrSize; j++) {
cJSON *arr2 = cJSON_GetArrayItem(arr, j); // 再進(jìn)一步解析就可以得到數(shù)組里面的元素了
if (arr2 != NULL && arr2->type == cJSON_String) {
v_str = arr2->valuestring;
printf("education = %s\n", v_str);
}
}
}
}
}
/*************** 方式二 ***************/
item = cJSON_GetObjectItem(root, "education");
if (item != NULL) {
cJSON *arr = item->child; // 獲得 [ "小學(xué)", "初中" ]
while (arr) {
if (arr->type == cJSON_Array) {
cJSON *arrValue = arr->child; // 獲得 "小學(xué)"
while (arrValue) {
if (arrValue->type == cJSON_String) {
char *v_str = arrValue->valuestring;
printf("education = %s\n", v_str);
}
arrValue = arrValue->next; // 獲取下一個(gè)元素
}
}
// 獲取下一組
arr = arr->next;
}
}
}
解析 對(duì)象 中 對(duì)象 { { } }
也就是解析下圖內(nèi)容:

解析代碼:
{
/*************** 方式一 ***************/
char *arrStr[] = { "serialOne", "serialTwo" }; // 可以提前定義需要解析的對(duì)象鍵,這樣就可以使用for循環(huán)進(jìn)行解析了
item = cJSON_GetObjectItem(root, "languages");
if (item != NULL) {
cJSON *val = NULL;
int size = sizeof(arrStr) / sizeof(char *);
// 通過(guò)遍歷指針數(shù)組,獲得每個(gè)對(duì)象的鍵,在進(jìn)行解析操作(如果不使用for循環(huán)解析,那就老老實(shí)實(shí)的寫代碼將全部個(gè)數(shù)解析完畢)
for (int i = 0; i < size; i++) {
cJSON *obj1 = cJSON_GetObjectItem(item, arrStr[i]);
if (obj1 != NULL && obj1->type == cJSON_Object) {
val = cJSON_GetObjectItem(obj1, "language");
if (val != NULL && val->type == cJSON_String) {
v_str = val->valuestring;
printf("education = %s\n", v_str);
}
val = cJSON_GetObjectItem(obj1, "grade");
if (val != NULL && val->type == cJSON_Number) {
v_int = val->valueint;
printf("grade = %d\n", v_int);
}
}
}
}
/*************** 方式二 ***************/
// 在不知道鍵是什么的情況下 和 不知道有多少元素的情況下可用
item = cJSON_GetObjectItem(root, "languages");
if (item != NULL) {
// 獲取到languages里的第一個(gè)子元素
cJSON *obj = item->child; // 也就是:"serialOne": { "language": "漢語(yǔ)", "grade": 10 }
while (obj) {
if (obj->type == cJSON_Object) {
// 獲取到子元素的子元素
cJSON *value = obj->child; // 也就是:{ "language": "漢語(yǔ)", "grade": 10 }
while (value) {
if (value->type == cJSON_String) {
printf("%s = %s\n", value->string, value->valuestring);
} else if (value->type == cJSON_Number) {
printf("%s = %d\n", value->string, value->valueint);
}
// 通過(guò)next可以自由獲取里面的元素了
value = value->next;
}
}
// 獲得下一組子元素
obj = obj->next;
}
}
}
解析結(jié)果如下:
因?yàn)橛袃煞N解析方式,所以他們都打印了兩遍!

五、修改Json
修改只是使用到兩個(gè)函數(shù)就可以了:
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
只不過(guò)得先定位到對(duì)應(yīng)的cJSON指針!
打開(kāi)文件、讀取json數(shù)據(jù),初始化cJSON這些與上面重復(fù)
// 將讀取到的json字符串轉(zhuǎn)換成json變量指針 cJSON *root = cJSON_Parse(jsonStr);
定義下面所需要用到的變量
// 這個(gè)變量用于接收定位到的cJSON cJSON *item = NULL;
直接進(jìn)行接修改的
/* "name": "小明" ====> "name": "小紅" */
// 使用cJSON_ReplaceItemInObject可以直接進(jìn)行修改
cJSON_ReplaceItemInObject(root, "name", cJSON_CreateString("小紅"));
/* "age": 23 ====> "age": 20 */
cJSON_ReplaceItemInObject(root, "age", cJSON_CreateNumber(20));
/* "vip": true ====> "vip": false */
// 使用cJSON_ReplaceItemInObject可以直接進(jìn)行修改
cJSON_ReplaceItemInObject(root, "vip", cJSON_CreateBool(false));
修改前:

修改后:

修改 { } 中的值
/*
"interest": { 修改后: "interest": {
"basketball": "籃球", ====> "basketball": "姚明",
"badminton": "羽毛球" "badminton": "林丹"
} }
*/
// 首先獲取到需要修改的指針
item = cJSON_GetObjectItem(root, "interest");
if (item != NULL) {
// 使用cJSON_ReplaceItemInObject可以直接進(jìn)行修改
cJSON_ReplaceItemInObject(item, "basketball", cJSON_CreateString("姚明"));
cJSON_ReplaceItemInObject(item, "badminton", cJSON_CreateString("林丹"));
}
修改前:

修改后:

修改數(shù)組 [ ] 中的元素
/* "color": ["black", "white"] ====> "color":["red", "blue"] */
item = cJSON_GetObjectItem(root, "color");
if (item != NULL) {
// 還是得通過(guò)索引去定位到具體需要修改的值
cJSON_ReplaceItemInArray(item, 0, cJSON_CreateString("red"));
cJSON_ReplaceItemInArray(item, 1, cJSON_CreateString("blue"));
}
修改前:

修改后:

修改 [ { } ] 中的值
/*
"like": [ 修改后: "like": [
{ "game": "馬里奧", "price": 66.6 }, ====> { "game": "炸彈人", "price": 88.8 },
{ "game": "魂斗羅", "price": 77.7 } { "game": "中國(guó)象棋", "price": 99.9 }
], ],
*/
item = cJSON_GetObjectItem(root, "like");
if (item != NULL) {
cJSON *arrObj = NULL;
arrObj = cJSON_GetArrayItem(item, 0); // 根據(jù)索引獲得數(shù)組中的值
cJSON_ReplaceItemInObject(arrObj, "game", cJSON_CreateString("炸彈人"));
cJSON_ReplaceItemInObject(arrObj, "price", cJSON_CreateNumber(88.8));
arrObj = cJSON_GetArrayItem(item, 1); // 根據(jù)索引獲得數(shù)組中的值
cJSON_ReplaceItemInObject(arrObj, "game", cJSON_CreateString("中國(guó)象棋"));
cJSON_ReplaceItemInObject(arrObj, "price", cJSON_CreateNumber(99.9));
}
修改前:

修改后:

修改 [ [ ] ] 中的值
/*
"education": [ 修改后: "education": [
[ "小學(xué)", "初中" ], ====> [ "小學(xué)六年級(jí)", "初中初三" ],
[ "高中", "大學(xué)" ] [ "高中高三", "大學(xué)大四" ]
], ],
*/
item = cJSON_GetObjectItem(root, "education");
if (item != NULL) {
cJSON *arrArr = NULL;
arrArr = cJSON_GetArrayItem(item, 0); // 根據(jù)索引獲得數(shù)組中的值
cJSON_ReplaceItemInArray(arrArr, 0, cJSON_CreateString("小學(xué)六年級(jí)"));
cJSON_ReplaceItemInArray(arrArr, 1, cJSON_CreateString("初中初三"));
arrArr = cJSON_GetArrayItem(item, 1); // 根據(jù)索引獲得數(shù)組中的值
cJSON_ReplaceItemInArray(arrArr, 0, cJSON_CreateString("高中高三"));
cJSON_ReplaceItemInArray(arrArr, 1, cJSON_CreateString("大學(xué)大四"));
}
修改前:

修改后:

修改 { { } } 中的值
/*
"languages": { 修改后: "languages": {
"serialOne": { "language": "漢語(yǔ)", "grade": 10 }, ====> "serialOne": { "language": "粵語(yǔ)", "grade": 9 },
"serialTwo": { "language": "英語(yǔ)", "grade": 6} "serialTwo": { "language": "白話", "grade": 8 }
}, },
*/
item = cJSON_GetObjectItem(root, "languages");
if (item != NULL) {
cJSON *obj = NULL;
obj = cJSON_GetObjectItem(item, "serialOne");
// 使用cJSON_ReplaceItemInObject可以直接進(jìn)行修改
cJSON_ReplaceItemInObject(obj, "language", cJSON_CreateString("粵語(yǔ)"));
cJSON_ReplaceItemInObject(obj, "grade", cJSON_CreateNumber(9));
obj = cJSON_GetObjectItem(item, "serialTwo");
// 使用cJSON_ReplaceItemInObject可以直接進(jìn)行修改
cJSON_ReplaceItemInObject(obj, "language", cJSON_CreateString("白話"));
cJSON_ReplaceItemInObject(obj, "grade", cJSON_CreateNumber(8));
}
修改前:

修改后:

寫入文件
// 打開(kāi)文件
file = fopen(FILE_NAME, "w");
if (file == NULL) {
printf("Open file fail!\n");
// 釋放指針內(nèi)存
cJSON_Delete(root);
return;
}
char *cjValue = cJSON_Print(root);
// 寫入文件
int ret = fwrite(cjValue, sizeof(char), strlen(cjValue), file);
if (ret == 0) {
printf("寫入文件失敗!\n");
}
fclose(file);
free(cjValue);
釋放root指針
// 使用了cJSON_Parse之后,記得調(diào)用cJSON_Delete函數(shù)釋放 cJSON_Delete(root);
六、刪除Json
刪除也是只用兩個(gè)函數(shù)即可:
extern void cJSON_DeleteItemFromArray(cJSON *array,int which); extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
找到對(duì)應(yīng)的cJOSN指針后,刪除數(shù)組指定索引,刪除對(duì)象指定鍵即可!
打開(kāi)文件、讀取json數(shù)據(jù),初始化cJSON這些與上面重復(fù)
// 將讀取到的json字符串轉(zhuǎn)換成json變量指針 cJSON *root = cJSON_Parse(jsonStr);
定義下面所需要用到的變量
// 這個(gè)變量用于接收定位到的cJSON cJSON *item = NULL;
直接進(jìn)行刪除的
/* 刪除: "name": "小紅" */ // 使用這個(gè)函數(shù)直接進(jìn)行刪除 cJSON_DeleteItemFromObject(root, "name"); // 通過(guò)鍵進(jìn)行刪除
刪除 { } 中的值
/* 刪除:
"interest": {
"badminton": "林丹"
}
*/
item = cJSON_GetObjectItem(root, "interest");
// 獲取到對(duì)應(yīng)的節(jié)點(diǎn)對(duì)象就可以直接刪除了
if (item != NULL) {
cJSON_DeleteItemFromObject(item, "badminton");
}
刪除前:

刪除后:

刪除數(shù)組[ ]中的元素
/* 刪除: "color": ["blue"] */
item = cJSON_GetObjectItem(root, "color");
// 獲取到對(duì)應(yīng)的節(jié)點(diǎn)數(shù)組就可以直接刪除了
if (item != NULL) {
cJSON_DeleteItemFromArray(item, 1); // 通過(guò)索引進(jìn)行刪除
}
刪除前:

刪除后:

刪除 [ ] 中的 { }
/* 刪除:
"like": [
{ "game": "炸彈人", "price": 88.800000 },
]
*/
item = cJSON_GetObjectItem(root, "like");
if (item != NULL) {
cJSON_DeleteItemFromArray(item, 0);
還可以再繼續(xù)深入進(jìn)行刪除
//cJSON *arrObj = cJSON_GetArrayItem(item, 0); // 根據(jù)索引獲得數(shù)組中的值
//if (arrObj != NULL) {
// cJSON_DeleteItemFromObject(arrObj, "price");
//}
}
刪除前:

刪除后:

刪除 [ ] 中的 [ ]
/* 刪除: "education": [["高中高三", "大學(xué)大四"]] */
item = cJSON_GetObjectItem(root, "education");
if (item != NULL) {
cJSON_DeleteItemFromArray(item, 1);
還可以再繼續(xù)深入進(jìn)行刪除
//cJSON *arrArr = cJSON_GetArrayItem(item, 0); // 根據(jù)索引獲得數(shù)組中的值
//if (arrArr != NULL) {
// cJSON_DeleteItemFromArray(arrArr, 1);
//}
}
刪除前:

刪除后:

刪除 { } 中的 { }
/* 刪除
"languages": {
"serialTwo": { "language":"白話", "grade":8 }
}
*/
item = cJSON_GetObjectItem(root, "languages");
if (item != NULL) {
cJSON_DeleteItemFromObject(item, "serialTwo");
還可以再繼續(xù)深入進(jìn)行刪除
//cJSON *obj = cJSON_GetObjectItem(item, "serialOne");
//if (obj != NULL) {
// cJSON_DeleteItemFromObject(obj, "grade");
//}
}
刪除前:

刪除后:

寫入文件
// 打開(kāi)文件
file = fopen(FILE_NAME, "w");
if (file == NULL) {
printf("Open file fail!\n");
// 釋放指針內(nèi)存
cJSON_Delete(root);
return;
}
char *cjValue = cJSON_Print(root);
// 寫入文件
int ret = fwrite(cjValue, sizeof(char), strlen(cjValue), file);
if (ret == 0) {
printf("寫入文件失??!\n");
}
fclose(file);
free(cjValue);
釋放cJSON指針內(nèi)存
// 使用了cJSON_Parse之后,記得調(diào)用cJSON_Delete函數(shù)釋放 cJSON_Delete(root);
七、全部代碼
在VS2017及其以上的版本中,新建一個(gè)空項(xiàng)目,將代碼拷貝過(guò)去,再導(dǎo)入cJSON.h 和 cJSON.c 文件即可運(yùn)行!
#include <stdio.h>
#include <malloc.h>
#include <memory.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/stat.h> // 獲取文件大小
#include "cJSON.h"
#define FILE_NAME "jss.json"
// 封裝Json
void createJson ();
// 解析Json
void parseJson();
// 修改Json
void alterJson();
// 刪除Json
void delJson();
int main (void) {
createJson();
parseJson();
alterJson();
delJson();
return 0;
}
void createJson () {
/*
"interest": {
"basketball": "籃球",
"badminton": "羽毛球"
},
*/
// 定義對(duì)象 { }
cJSON *interest = cJSON_CreateObject();
// 插入元素,對(duì)應(yīng) 鍵值對(duì)
cJSON_AddItemToObject(interest, "basketball", cJSON_CreateString("籃球")); // 當(dāng)值是字符串時(shí),需要使用函數(shù)cJSON_CreateString()創(chuàng)建
cJSON_AddItemToObject(interest, "badminton", cJSON_CreateString("羽毛球"));
//cJSON_AddStringToObject(interest, "badminton", "羽毛球"); // 或者這樣寫
/*
"color": [ "black", "white" ],
*/
// 定義 [ ] 數(shù)組
cJSON *color = cJSON_CreateArray();
// 往數(shù)組中添加元素
cJSON_AddItemToArray(color, cJSON_CreateString("black"));
cJSON_AddItemToArray(color, cJSON_CreateString("white"));
/*
"like": [
{ "game": "馬里奧", "price": 66.6 },
{ "game": "魂斗羅", "price": 77.7 }
],
*/
// 定義 { } 對(duì)象
cJSON *likeObject1 = cJSON_CreateObject();
cJSON_AddItemToObject(likeObject1, "game", cJSON_CreateString("馬里奧"));
cJSON_AddItemToObject(likeObject1, "price", cJSON_CreateNumber(66.6)); // 當(dāng)值是數(shù)字時(shí),需要使用函數(shù)cJSON_CreateNumber()創(chuàng)建
//cJSON_AddNumberToObject(likeObject1, "price", 66.6); // 或者這樣寫
cJSON *likeObject2 = cJSON_CreateObject();
cJSON_AddItemToObject(likeObject2, "game", cJSON_CreateString("魂斗羅"));
cJSON_AddItemToObject(likeObject2, "price", cJSON_CreateNumber(77.7));
// 定義 [ ] 數(shù)組
cJSON *like = cJSON_CreateArray();
// 往數(shù)組中添加元素
cJSON_AddItemToArray(like, likeObject1);
cJSON_AddItemToArray(like, likeObject2);
/*
"education": [
[ "小學(xué)", "初中" ],
[ "高中", "大學(xué)" ]
],
*/
// 定義 [ ] 數(shù)組
cJSON *education1 = cJSON_CreateArray();
cJSON_AddItemToArray(education1, cJSON_CreateString("小學(xué)"));
cJSON_AddItemToArray(education1, cJSON_CreateString("初中"));
cJSON *education2 = cJSON_CreateArray();
cJSON_AddItemToArray(education2, cJSON_CreateString("高中"));
cJSON_AddItemToArray(education2, cJSON_CreateString("大學(xué)"));
// 定義 [ ] 數(shù)組
cJSON *education = cJSON_CreateArray();
cJSON_AddItemToArray(education, education1);
cJSON_AddItemToArray(education, education2);
/*
"languages": {
"serialOne": { "language": "漢語(yǔ)", "grade": 10 },
"serialTwo": { "language": "英語(yǔ)", "grade": 6}
},
*/
// 定義對(duì)象 { }
cJSON *serialOne = cJSON_CreateObject();
cJSON_AddItemToObject(serialOne, "language", cJSON_CreateString("漢語(yǔ)"));
cJSON_AddItemToObject(serialOne, "grade", cJSON_CreateNumber(10));
cJSON *serialTwo = cJSON_CreateObject();
cJSON_AddItemToObject(serialTwo, "language", cJSON_CreateString("英語(yǔ)"));
cJSON_AddItemToObject(serialTwo, "grade", cJSON_CreateNumber(6));
// 定義對(duì)象 { }
cJSON *languages = cJSON_CreateObject();
cJSON_AddItemToObject(languages, "serialOne", serialOne);
cJSON_AddItemToObject(languages, "serialTwo", serialTwo);
// 創(chuàng)建跟對(duì)象
cJSON *root = cJSON_CreateObject();
// 將子項(xiàng)插入根項(xiàng)中
cJSON_AddItemToObject(root, "name", cJSON_CreateString("小明")); // "name": "小明"
cJSON_AddItemToObject(root, "age", cJSON_CreateNumber(23)); // "age": 23
cJSON_AddItemToObject(root, "interest", interest);
cJSON_AddItemToObject(root, "color", color);
cJSON_AddItemToObject(root, "like", like);
cJSON_AddItemToObject(root, "education", education);
cJSON_AddItemToObject(root, "languages", languages);
cJSON_AddItemToObject(root, "vip", cJSON_CreateTrue()); // "vip": true 插入布爾類型數(shù)據(jù)需要使用cJSON_CreateBool函數(shù)
cJSON_AddItemToObject(root, "address", cJSON_CreateNull()); // "address": null 插入NULL值需要使用cJSON_CreateNull函數(shù)
//cJSON_AddTrueToObject(root, "vip");
//cJSON_AddNullToObject(root, "address"); // 或者這樣寫也是可以的
// 打印控制臺(tái)查看
char *cPrint = cJSON_Print(root);
char *cPrintUnformatted = cJSON_PrintUnformatted(root);
printf("cJSON_Print:\n%s\n\n\n", cPrint); // cJSON_Print:有做格式調(diào)整
printf("cJSON_PrintUnformatted:\n%s\n\n\n", cPrintUnformatted); // cJSON_PrintUnformatted:沒(méi)有做格式調(diào)整
// 返回的字符串指針需要自己釋放
free(cPrint);
free(cPrintUnformatted);
// 打開(kāi)文件
FILE *file = NULL;
file = fopen(FILE_NAME, "w"); // FILE_NAME ==> "jss.json"
if (file == NULL) {
printf("Open file fail!\n");
// 釋放指針內(nèi)存
cJSON_Delete(root);
return;
}
char *cjValue = cJSON_Print(root);
// 寫入文件
//int ret = fwrite(cjValue, sizeof(char), strlen(cjValue), file);
int ret = fputs(cjValue, file);
if (ret == EOF) {
printf("寫入文件失?。n");
}
fclose(file);
free(cjValue);
// 釋放指針內(nèi)存
cJSON_Delete(root);
}
void parseJson () {
// 打開(kāi)文件
FILE *file = NULL;
file = fopen(FILE_NAME, "r");
if (file == NULL) {
printf("Open file fail!\n");
return;
}
// 獲得文件大小
struct stat statbuf;
stat(FILE_NAME, &statbuf);
int fileSize = statbuf.st_size;
printf("文件大?。?d\n", fileSize);
// 分配符合文件大小的內(nèi)存
char *jsonStr = (char *)malloc(sizeof(char) * fileSize + 1);
memset(jsonStr, 0, fileSize + 1);
// 讀取文件中的json字符串
int size = fread(jsonStr, sizeof(char), fileSize, file);
if (size == 0) {
printf("讀取文件失??!\n");
return;
}
printf("%s\n", jsonStr);
fclose(file);
// 將讀取到的json字符串轉(zhuǎn)換成json變量指針
cJSON *root = cJSON_Parse(jsonStr);
if (!root) {
const char *err = cJSON_GetErrorPtr();
printf("Error before: [%s]\n", err);
free((void *)err);
free(jsonStr);
return;
}
free(jsonStr);
cJSON *item = NULL;
char *v_str = NULL;
double v_double = 0.0;
int v_int = 0;
bool v_bool = false;
// 解析:"name": "小明",
item = cJSON_GetObjectItem(root, "name");
if (item != NULL) {
/* 寫法一:*/
// 判斷是不是字符串類型
//if (item->type == cJSON_String) {
// v_str = cJSON_Print(item); // 通過(guò)函數(shù)獲取值
// printf("name = %s\n", v_str);
// free(v_str); // 通過(guò)函數(shù)返回的指針需要自行free,否則會(huì)導(dǎo)致內(nèi)存泄漏
// v_str = NULL;
//}
/* 寫法二: */
// 判斷是不是字符串類型
if (item->type == cJSON_String) {
v_str = item->valuestring; // 此賦值是淺拷貝,不需要現(xiàn)在釋放內(nèi)存
printf("name = %s\n", v_str);
}
}
// 解析:"age": "23",
item = cJSON_GetObjectItem(root, "age");
if (item != NULL) { // 合法性檢查
if (item->type == cJSON_Number) { // 判斷是不是數(shù)字
v_int = item->valueint; // 獲取值
printf("age = %d\n", v_int);
}
}
// 解析:"vip": true,
item = cJSON_GetObjectItem(root, "vip");
if (item != NULL) {
if (item->type == cJSON_True || item->type == cJSON_False) {
v_str = cJSON_Print(item); // 由于bool類型結(jié)構(gòu)體中沒(méi)有給出,所以使用字符串代替
printf("vip = %s\n", v_str);
free(v_str);
v_str = NULL;
}
}
// 解析:"address": null
item = cJSON_GetObjectItem(root, "address");
if (item != NULL && item->type == cJSON_NULL) {
v_str = cJSON_Print(item); // 由于NULL類型結(jié)構(gòu)體中沒(méi)有給出,所以使用字符串代替
printf("address = %s\n", v_str);
free(v_str);
v_str = NULL;
}
/* 解析:
"interest": {
"basketball": "籃球",
"badminton": "羽毛球"
},
*/
{
/*************** 方式一 ***************/
item = cJSON_GetObjectItem(root, "interest"); // 獲取object對(duì)象名
if (item != NULL) {
cJSON *val = NULL;
val = cJSON_GetObjectItem(item, "basketball"); // 根據(jù)object對(duì)象名獲得里面的basketball數(shù)據(jù)
if (val != NULL && val->type == cJSON_String) {
v_str = val->valuestring;
printf("basketball = %s\n", v_str);
}
val = cJSON_GetObjectItem(item, "badminton"); // 根據(jù)object對(duì)象名獲得里面的badminton數(shù)據(jù)
if (val != NULL && val->type == cJSON_String) {
v_str = val->valuestring;
printf("badminton = %s\n", v_str);
}
}
/*************** 方式二 ***************/
item = cJSON_GetObjectItem(root, "interest");
if (item != NULL) {
cJSON *obj = item->child; // 獲得 "basketball": "籃球"
while (obj) {
if (obj->type == cJSON_String) {
char *v_str = obj->valuestring;
printf("%s = %s\n", obj->string, v_str); // 可以通過(guò)string獲得鍵
}
// 獲取下一個(gè)元素
obj = obj->next;
}
}
}
/* 解析:
"color": ["black", "white"],
*/
{
/*************** 方式一 ***************/
item = cJSON_GetObjectItem(root, "color");
if (item != NULL) {
int size = cJSON_GetArraySize(item); // 獲得數(shù)組個(gè)數(shù)
for (int i = 0; i < size; i++) {
cJSON *arr = cJSON_GetArrayItem(item, i); // 根據(jù)索引獲得數(shù)組中的值
if (arr != NULL && arr->type == cJSON_String) {
v_str = arr->valuestring;
printf("color = %s\n", v_str);
}
}
}
/*************** 方式二 ***************/
item = cJSON_GetObjectItem(root, "color");
if (item != NULL) {
cJSON *arr = item->child; // 獲得 "black"
while (arr) {
if (arr->type == cJSON_String) {
char *v_str = arr->valuestring;
printf("color = %s\n", v_str);
}
// 獲取下一個(gè)元素
arr = arr->next;
}
}
}
/*
"like": [
{ "game": "馬里奧", "price": 66.6 },
{ "game": "魂斗羅", "price": 77.7 }
],
*/
{
/*************** 方式一 ***************/
item = cJSON_GetObjectItem(root, "like");
if (item != NULL) {
int size = cJSON_GetArraySize(item); // 獲取的數(shù)組大小
for (int i = 0; i < size; i++) {
cJSON *obj = cJSON_GetArrayItem(item, i); // 獲取的數(shù)組里的obj
cJSON *val = NULL;
if (obj != NULL && obj->type == cJSON_Object) { // 判斷數(shù)字內(nèi)的元素是不是obj類型
val = cJSON_GetObjectItem(obj, "game"); // 獲得obj里的值
if (val != NULL && val->type == cJSON_String) {
v_str = val->valuestring;
printf("game = %s\n", v_str);
}
val = cJSON_GetObjectItem(obj, "price");
if (val != NULL && val->type == cJSON_Number) {
v_double = val->valuedouble;
printf("price = %.2f\n", v_double);
}
}
}
}
/*************** 方式二 ***************/
item = cJSON_GetObjectItem(root, "like");
if (item != NULL) {
cJSON *obj = item->child; // 獲得 { "game": "馬里奧", "price": 66.6 }
while (obj) {
if (obj->type == cJSON_Object) {
cJSON *objValue = obj->child; // 獲得 "game": "馬里奧"
while (objValue) {
// 再通過(guò)類型去區(qū)分
if (objValue->type == cJSON_String) {
char *v_str = objValue->valuestring;
printf("%s = %s\n", objValue->string, v_str);
} else if (objValue->type == cJSON_Number) {
double v_double = objValue->valuedouble;
printf("%s = %.2f\n", objValue->string, v_double);
}
// 獲取下一個(gè)元素
objValue = objValue->next;
}
}
// 獲取下一組元素
obj = obj->next;
}
}
}
/*
"education": [
[ "小學(xué)", "初中" ],
[ "高中", "大學(xué)" ]
],
*/
{
/*************** 方式一 ***************/
item = cJSON_GetObjectItem(root, "education");
if (item != NULL) {
int size = cJSON_GetArraySize(item); // 獲取的數(shù)組大小
for (int i = 0; i < size; i++) {
cJSON *arr = cJSON_GetArrayItem(item, i); // 解析獲得 [ "小學(xué)", "初中" ]
if (arr != NULL && arr->type == cJSON_Array) {
int arrSize = cJSON_GetArraySize(arr);
for (int j = 0; j < arrSize; j++) {
cJSON *arr2 = cJSON_GetArrayItem(arr, j); // 再進(jìn)一步解析就可以得到數(shù)組里面的元素了
if (arr2 != NULL && arr2->type == cJSON_String) {
v_str = arr2->valuestring;
printf("education = %s\n", v_str);
}
}
}
}
}
/*************** 方式二 ***************/
item = cJSON_GetObjectItem(root, "education");
if (item != NULL) {
cJSON *arr = item->child; // 獲得 [ "小學(xué)", "初中" ]
while (arr) {
if (arr->type == cJSON_Array) {
cJSON *arrValue = arr->child; // 獲得 "小學(xué)"
while (arrValue) {
if (arrValue->type == cJSON_String) {
char *v_str = arrValue->valuestring;
printf("education = %s\n", v_str);
}
arrValue = arrValue->next; // 獲取下一個(gè)元素
}
}
// 獲取下一組
arr = arr->next;
}
}
}
/*
"languages": {
"serialOne": { "language": "漢語(yǔ)", "grade": 10 },
"serialTwo": { "language": "英語(yǔ)", "grade": 6}
},
*/
{
/*************** 方式一 ***************/
char *arrStr[] = { "serialOne", "serialTwo" }; // 可以提前定義需要解析的對(duì)象鍵,這樣就可以使用for循環(huán)進(jìn)行解析了
item = cJSON_GetObjectItem(root, "languages");
if (item != NULL) {
cJSON *val = NULL;
int size = sizeof(arrStr) / sizeof(char *);
// 通過(guò)遍歷指針數(shù)組,獲得每個(gè)對(duì)象的鍵,在進(jìn)行解析操作(如果不使用for循環(huán)解析,那就老老實(shí)實(shí)的寫代碼將全部個(gè)數(shù)解析完畢)
for (int i = 0; i < size; i++) {
cJSON *obj1 = cJSON_GetObjectItem(item, arrStr[i]);
if (obj1 != NULL && obj1->type == cJSON_Object) {
val = cJSON_GetObjectItem(obj1, "language");
if (val != NULL && val->type == cJSON_String) {
v_str = val->valuestring;
printf("education = %s\n", v_str);
}
val = cJSON_GetObjectItem(obj1, "grade");
if (val != NULL && val->type == cJSON_Number) {
v_int = val->valueint;
printf("grade = %d\n", v_int);
}
}
}
}
/*************** 方式二 ***************/
// 在不知道鍵是什么的情況下 和 不知道有多少元素的情況下可用
item = cJSON_GetObjectItem(root, "languages");
if (item != NULL) {
// 獲取到languages里的第一個(gè)子元素
cJSON *obj = item->child; // 也就是:"serialOne": { "language": "漢語(yǔ)", "grade": 10 }
while (obj) {
if (obj->type == cJSON_Object) {
// 獲取到子元素的子元素
cJSON *value = obj->child; // 也就是:{ "language": "漢語(yǔ)", "grade": 10 }
while (value) {
if (value->type == cJSON_String) {
printf("%s = %s\n", value->string, value->valuestring);
} else if (value->type == cJSON_Number) {
printf("%s = %d\n", value->string, value->valueint);
}
// 通過(guò)next可以自由獲取里面的元素了
value = value->next;
}
}
// 獲得下一組子元素
obj = obj->next;
}
}
}
// 使用了cJSON_Parse之后,記得調(diào)用cJSON_Delete函數(shù)釋放
cJSON_Delete(root);
}
void alterJson() {
// 打開(kāi)文件
FILE *file = NULL;
file = fopen(FILE_NAME, "r");
if (file == NULL) {
printf("Open file fail!\n");
return;
}
// 獲得文件大小
struct stat statbuf;
stat(FILE_NAME, &statbuf);
int fileSize = statbuf.st_size;
printf("文件大小:%d\n", fileSize);
// 分配符合文件大小的內(nèi)存
char *jsonStr = (char *)malloc(sizeof(char) * fileSize + 1);
memset(jsonStr, 0, fileSize + 1);
// 讀取文件中的json字符串
int size = fread(jsonStr, sizeof(char), fileSize, file);
if (size == 0) {
printf("讀取文件失敗!\n");
return;
}
printf("%s\n", jsonStr);
fclose(file);
// 將讀取到的json字符串轉(zhuǎn)換成json變量指針
cJSON *root = cJSON_Parse(jsonStr);
if (!root) {
const char *err = cJSON_GetErrorPtr();
printf("Error before: [%s]\n", err);
free((void *)err);
free(jsonStr);
return;
}
free(jsonStr);
cJSON *item = NULL;
/* "name": "小明" ====> "name": "小紅" */
// 使用cJSON_ReplaceItemInObject可以直接進(jìn)行修改
cJSON_ReplaceItemInObject(root, "name", cJSON_CreateString("小紅"));
// 解析打印查看是否修改成功
item = cJSON_GetObjectItem(root, "name");
if (item != NULL) {
// 判斷是不是字符串類型
if (item->type == cJSON_String) {
char *v_str = item->valuestring; // 此賦值是淺拷貝,不需要現(xiàn)在釋放內(nèi)存
printf("name = %s\n", v_str);
}
}
/* "age": 23 ====> "age": 20 */
cJSON_ReplaceItemInObject(root, "age", cJSON_CreateNumber(20));
// 解析打印查看是否修改成功
item = cJSON_GetObjectItem(root, "age");
if (item != NULL) {
// 判斷是不是字符串類型
if (item->type == cJSON_Number) {
int v_int = item->valueint;
printf("age = %d\n", v_int);
}
}
/* "vip": true ====> "vip": false */
// 使用cJSON_ReplaceItemInObject可以直接進(jìn)行修改
cJSON_ReplaceItemInObject(root, "vip", cJSON_CreateBool(false));
// 解析打印查看是否修改成功
item = cJSON_GetObjectItem(root, "vip");
if (item != NULL) {
// 判斷是不是字符串類型
if (item->type == cJSON_False || item->type == cJSON_True) {
char *v_str = cJSON_Print(item); // 由于bool類型結(jié)構(gòu)體中沒(méi)有給出,所以使用字符串代替
printf("vip = %s\n", v_str);
free(v_str);
v_str = NULL;
}
}
/*
"interest": { 修改后: "interest": {
"basketball": "籃球", ====> "basketball": "姚明",
"badminton": "羽毛球" "badminton": "林丹"
} }
*/
// 首先獲取到需要修改的指針
item = cJSON_GetObjectItem(root, "interest");
if (item != NULL) {
// 使用cJSON_ReplaceItemInObject可以直接進(jìn)行修改
cJSON_ReplaceItemInObject(item, "basketball", cJSON_CreateString("姚明"));
cJSON_ReplaceItemInObject(item, "badminton", cJSON_CreateString("林丹"));
}
// 解析打印查看是否修改成功
item = cJSON_GetObjectItem(root, "interest");
if (item != NULL) {
cJSON *obj = item->child; // 獲得 "basketball": "籃球"
while (obj) {
if (obj->type == cJSON_String) {
char *v_str = obj->valuestring;
printf("%s = %s\n", obj->string, v_str); // 可以通過(guò)string獲得鍵
}
// 獲取下一個(gè)元素
obj = obj->next;
}
}
/* "color": ["black", "white"] ====> "color":["red", "blue"] */
item = cJSON_GetObjectItem(root, "color");
if (item != NULL) {
cJSON_ReplaceItemInArray(item, 0, cJSON_CreateString("red"));
cJSON_ReplaceItemInArray(item, 1, cJSON_CreateString("blue"));
}
// 解析打印查看是否修改成功
item = cJSON_GetObjectItem(root, "color");
if (item != NULL) {
cJSON *arr = item->child; // 獲得 "black"
while (arr) {
if (arr->type == cJSON_String) {
char *v_str = arr->valuestring;
printf("color = %s\n", v_str);
}
// 獲取下一個(gè)元素
arr = arr->next;
}
}
/*
"like": [ 修改后: "like": [
{ "game": "馬里奧", "price": 66.6 }, ====> { "game": "炸彈人", "price": 88.8 },
{ "game": "魂斗羅", "price": 77.7 } { "game": "中國(guó)象棋", "price": 99.9 }
], ],
*/
item = cJSON_GetObjectItem(root, "like");
if (item != NULL) {
cJSON *arrObj = NULL;
arrObj = cJSON_GetArrayItem(item, 0); // 根據(jù)索引獲得數(shù)組中的值
cJSON_ReplaceItemInObject(arrObj, "game", cJSON_CreateString("炸彈人"));
cJSON_ReplaceItemInObject(arrObj, "price", cJSON_CreateNumber(88.8));
arrObj = cJSON_GetArrayItem(item, 1); // 根據(jù)索引獲得數(shù)組中的值
cJSON_ReplaceItemInObject(arrObj, "game", cJSON_CreateString("中國(guó)象棋"));
cJSON_ReplaceItemInObject(arrObj, "price", cJSON_CreateNumber(99.9));
}
// 解析打印查看是否修改成功
item = cJSON_GetObjectItem(root, "like");
if (item != NULL) {
cJSON *obj = item->child; // 獲得 { "game": "馬里奧", "price": 66.6 }
while (obj) {
if (obj->type == cJSON_Object) {
cJSON *objValue = obj->child; // 獲得 "game": "馬里奧"
while (objValue) {
// 再通過(guò)類型去區(qū)分
if (objValue->type == cJSON_String) {
char *v_str = objValue->valuestring;
printf("%s = %s\n", objValue->string, v_str);
} else if (objValue->type == cJSON_Number) {
double v_double = objValue->valuedouble;
printf("%s = %.2f\n", objValue->string, v_double);
}
// 獲取下一個(gè)元素
objValue = objValue->next;
}
}
// 獲取下一組元素
obj = obj->next;
}
}
/*
"education": [ 修改后: "education": [
[ "小學(xué)", "初中" ], ====> [ "小學(xué)六年級(jí)", "初中初三" ],
[ "高中", "大學(xué)" ] [ "高中高三", "大學(xué)大四" ]
], ],
*/
item = cJSON_GetObjectItem(root, "education");
if (item != NULL) {
cJSON *arrArr = NULL;
arrArr = cJSON_GetArrayItem(item, 0); // 根據(jù)索引獲得數(shù)組中的值
cJSON_ReplaceItemInArray(arrArr, 0, cJSON_CreateString("小學(xué)六年級(jí)"));
cJSON_ReplaceItemInArray(arrArr, 1, cJSON_CreateString("初中初三"));
arrArr = cJSON_GetArrayItem(item, 1); // 根據(jù)索引獲得數(shù)組中的值
cJSON_ReplaceItemInArray(arrArr, 0, cJSON_CreateString("高中高三"));
cJSON_ReplaceItemInArray(arrArr, 1, cJSON_CreateString("大學(xué)大四"));
}
// 解析打印查看是否修改成功
item = cJSON_GetObjectItem(root, "education");
if (item != NULL) {
cJSON *arr = item->child; // 獲得 [ "小學(xué)", "初中" ]
while (arr) {
if (arr->type == cJSON_Array) {
cJSON *arrValue = arr->child; // 獲得 "小學(xué)"
while (arrValue) {
if (arrValue->type == cJSON_String) {
char *v_str = arrValue->valuestring;
printf("education = %s\n", v_str);
}
arrValue = arrValue->next; // 獲取下一個(gè)元素
}
}
// 獲取下一組
arr = arr->next;
}
}
/*
"languages": { 修改后: "languages": {
"serialOne": { "language": "漢語(yǔ)", "grade": 10 }, ====> "serialOne": { "language": "粵語(yǔ)", "grade": 9 },
"serialTwo": { "language": "英語(yǔ)", "grade": 6} "serialTwo": { "language": "白話", "grade": 8 }
}, },
*/
item = cJSON_GetObjectItem(root, "languages");
if (item != NULL) {
cJSON *obj = NULL;
obj = cJSON_GetObjectItem(item, "serialOne");
// 使用cJSON_ReplaceItemInObject可以直接進(jìn)行修改
cJSON_ReplaceItemInObject(obj, "language", cJSON_CreateString("粵語(yǔ)"));
cJSON_ReplaceItemInObject(obj, "grade", cJSON_CreateNumber(9));
obj = cJSON_GetObjectItem(item, "serialTwo");
// 使用cJSON_ReplaceItemInObject可以直接進(jìn)行修改
cJSON_ReplaceItemInObject(obj, "language", cJSON_CreateString("白話"));
cJSON_ReplaceItemInObject(obj, "grade", cJSON_CreateNumber(8));
}
// 解析打印查看是否修改成功
item = cJSON_GetObjectItem(root, "languages");
if (item != NULL) {
// 獲取到languages里的第一個(gè)子元素
cJSON *obj = item->child; // 也就是:"serialOne": { "language": "漢語(yǔ)", "grade": 10 }
while (obj) {
if (obj->type == cJSON_Object) {
// 獲取到子元素的子元素
cJSON *value = obj->child; // 也就是:{ "language": "漢語(yǔ)", "grade": 10 }
while (value) {
if (value->type == cJSON_String) {
printf("%s = %s\n", value->string, value->valuestring);
} else if (value->type == cJSON_Number) {
printf("%s = %d\n", value->string, value->valueint);
}
// 通過(guò)next可以自由獲取里面的元素了
value = value->next;
}
}
obj = obj->next;
}
}
// 打開(kāi)文件
file = fopen(FILE_NAME, "w");
if (file == NULL) {
printf("Open file fail!\n");
// 釋放指針內(nèi)存
cJSON_Delete(root);
return;
}
char *cjValue = cJSON_Print(root);
// 寫入文件
int ret = fwrite(cjValue, sizeof(char), strlen(cjValue), file);
if (ret == 0) {
printf("寫入文件失?。n");
}
fclose(file);
free(cjValue);
// 使用了cJSON_Parse之后,記得調(diào)用cJSON_Delete函數(shù)釋放
cJSON_Delete(root);
}
void delJson() {
// 打開(kāi)文件
FILE *file = NULL;
file = fopen(FILE_NAME, "r");
if (file == NULL) {
printf("Open file fail!\n");
return;
}
// 獲得文件大小
struct stat statbuf;
stat(FILE_NAME, &statbuf);
int fileSize = statbuf.st_size;
printf("文件大?。?d\n", fileSize);
// 分配符合文件大小的內(nèi)存
char *jsonStr = (char *)malloc(sizeof(char) * fileSize + 1);
memset(jsonStr, 0, fileSize + 1);
// 讀取文件中的json字符串
int size = fread(jsonStr, sizeof(char), fileSize, file);
if (size == 0) {
printf("讀取文件失敗!\n");
return;
}
printf("%s\n", jsonStr);
fclose(file);
// 將讀取到的json字符串轉(zhuǎn)換成json變量指針
cJSON *root = cJSON_Parse(jsonStr);
if (!root) {
const char *err = cJSON_GetErrorPtr();
printf("Error before: [%s]\n", err);
free((void *)err);
free(jsonStr);
return;
}
free(jsonStr);
cJSON *item = NULL;
/* 刪除: "name": "小紅" */
// 使用這個(gè)函數(shù)直接進(jìn)行刪除
cJSON_DeleteItemFromObject(root, "name"); // 通過(guò)鍵進(jìn)行刪除
/* 刪除:
"interest": {
"badminton": "林丹"
}
*/
item = cJSON_GetObjectItem(root, "interest");
// 獲取到對(duì)應(yīng)的節(jié)點(diǎn)對(duì)象就可以直接刪除了
if (item != NULL) {
cJSON_DeleteItemFromObject(item, "badminton");
}
/* 刪除: "color": ["blue"] */
item = cJSON_GetObjectItem(root, "color");
// 獲取到對(duì)應(yīng)的節(jié)點(diǎn)數(shù)組就可以直接刪除了
if (item != NULL) {
cJSON_DeleteItemFromArray(item, 1); // 通過(guò)索引進(jìn)行刪除
}
/* 刪除:
"like": [
{ "game": "炸彈人", "price": 88.800000 },
]
*/
item = cJSON_GetObjectItem(root, "like");
if (item != NULL) {
cJSON_DeleteItemFromArray(item, 0);
還可以再繼續(xù)深入進(jìn)行刪除
//cJSON *arrObj = cJSON_GetArrayItem(item, 0); // 根據(jù)索引獲得數(shù)組中的值
//if (arrObj != NULL) {
// cJSON_DeleteItemFromObject(arrObj, "price");
//}
}
/* 刪除: "education": [["高中高三", "大學(xué)大四"]] */
item = cJSON_GetObjectItem(root, "education");
if (item != NULL) {
cJSON_DeleteItemFromArray(item, 1);
還可以再繼續(xù)深入進(jìn)行刪除
//cJSON *arrArr = cJSON_GetArrayItem(item, 0); // 根據(jù)索引獲得數(shù)組中的值
//if (arrArr != NULL) {
// cJSON_DeleteItemFromArray(arrArr, 1);
//}
}
/* 刪除
"languages": {
"serialTwo": { "language":"白話", "grade":8 }
}
*/
item = cJSON_GetObjectItem(root, "languages");
if (item != NULL) {
cJSON_DeleteItemFromObject(item, "serialTwo");
還可以再繼續(xù)深入進(jìn)行刪除
//cJSON *obj = cJSON_GetObjectItem(item, "serialOne");
//if (obj != NULL) {
// cJSON_DeleteItemFromObject(obj, "grade");
//}
}
// 打開(kāi)文件
file = fopen(FILE_NAME, "w");
if (file == NULL) {
printf("Open file fail!\n");
// 釋放指針內(nèi)存
cJSON_Delete(root);
return;
}
char *cjValue = cJSON_Print(root);
// 寫入文件
int ret = fwrite(cjValue, sizeof(char), strlen(cjValue), file);
if (ret == 0) {
printf("寫入文件失?。n");
}
fclose(file);
free(cjValue);
// 使用了cJSON_Parse之后,記得調(diào)用cJSON_Delete函數(shù)釋放
cJSON_Delete(root);
}
八、總結(jié)
寫這篇博客花了我好多好多好多時(shí)間,也確實(shí)挺累的,不過(guò)還好,最后還是按照自己意愿寫完了這篇博客!
其中,解析那一個(gè)模塊有兩種解析方式,建議使用第二種解析方式,比較靈活,即使后期再加多了幾個(gè)節(jié)點(diǎn),也照樣可以解析出來(lái),且無(wú)需再改動(dòng)代碼!
我個(gè)人感覺(jué),這篇博客對(duì)json的操作,應(yīng)該是很全面的了,幾乎涵蓋了所有的結(jié)果性,現(xiàn)在記錄下來(lái)分享給需要的各位!
到此這篇關(guān)于C++使用cjson操作Json格式文件(創(chuàng)建、插入、解析、修改、刪除)的文章就介紹到這了,更多相關(guān)C++使用cjson操作Json內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言陷阱與缺陷之?dāng)?shù)組越界訪問(wèn)詳解
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言的數(shù)組越界訪問(wèn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-02-02
C++實(shí)現(xiàn)與Lua相互調(diào)用的示例詳解
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)與Lua相互調(diào)用的方法,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解一下2023-03-03
GCC 編譯使用動(dòng)態(tài)鏈接庫(kù)和靜態(tài)鏈接庫(kù)的方法
根據(jù)鏈接時(shí)期的不同,庫(kù)又有靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)之分,有別于靜態(tài)庫(kù),動(dòng)態(tài)庫(kù)的鏈接是在程序執(zhí)行的時(shí)候被鏈接的2013-03-03
c語(yǔ)言程序設(shè)計(jì)文件操作方法示例(CreateFile和fopen)
c主要的文件操作函數(shù)有:CreateFile,CloseHandle,ReadFile,WriteFile,SetFilePointer,GetFileSize。其中的讀寫操作是以字符為單位,獲得文件大小也是以字符為單位。2013-12-12
C++實(shí)現(xiàn)約瑟夫環(huán)的循環(huán)單鏈表
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)約瑟夫環(huán)的循環(huán)單鏈表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10

