C++使用cjson操作Json格式文件(創(chuàng)建、插入、解析、修改、刪除)
為什么要學(xué)習(xí)解析Json文件?
工作需要唄!
最近在工作項(xiàng)目中,有需求是需要進(jìn)行解析Json字符串的,但是我只會(huì)使用QT去解析Json,且主管規(guī)定要使用C/C++語言去解析,說是為了方便移植到其他項(xiàng)目中進(jìn)行使用…
沒辦法,只能硬著頭皮,在網(wǎng)上找找有沒有什么解析Json的開源庫是C/C++可以使用的。
找了許多,網(wǎng)上也提供了許多,最終我選擇了cJOSN,不為什么,就是因?yàn)樗∏闪岘嚕沂羌僀的!
花了一兩周的悠閑時(shí)間去學(xué)習(xí),把一些比較常用的解析的JSON字符串解析解析記錄下來!
最后簡單介紹一下json是什么吧:
json是一個(gè)輕量級(jí)的數(shù)據(jù)存儲(chǔ)交換語言,其是通過鍵值對(duì)的形式存儲(chǔ)的,例如:{ “key” : “value” }
注意:鍵需要使用雙引號(hào)括起來,值如果是字符串也需要使用雙引號(hào)括起來,其他類型不需要。
json主要用來網(wǎng)絡(luò)數(shù)據(jù)傳輸!
一、準(zhǔn)備cJSON開源庫
cjosn庫下載網(wǎng)址:https://sourceforge.net/projects/cjson/
下載后會(huì)得到一個(gè)壓縮包,解壓后進(jìn)入里面拷貝cJSON.c和cJSON.h文件到自己的項(xiàng)目中去。
最后在自己的項(xiàng)目中把這兩個(gè)文件添加進(jìn)來即可!
Linux 和 Window下都可以使用!
二、cJSON介紹
首先介紹一下json數(shù)據(jù):
上圖的json數(shù)據(jù)就是這篇博客將要操作的,將會(huì)對(duì)其進(jìn)行創(chuàng)建、解析、修改、刪除操作。
其中這里包含項(xiàng)目中常用的封裝和解析。
cJSON主要是通過結(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è)沒有作格式調(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": "漢語", "grade": 10 }, "serialTwo": { "language": "英語", "grade": 6} }
代碼實(shí)現(xiàn)上述效果:
// 定義對(duì)象 { } cJSON *serialOne = cJSON_CreateObject(); cJSON_AddItemToObject(serialOne, "language", cJSON_CreateString("漢語")); cJSON_AddItemToObject(serialOne, "grade", cJSON_CreateNumber(10)); cJSON *serialTwo = cJSON_CreateObject(); cJSON_AddItemToObject(serialTwo, "language", cJSON_CreateString("英語")); 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:沒有做格式調(diào)整 // 返回的字符串指針需要自己釋放 free(cPrint); free(cPrintUnformatted);
記得使用cJSON_Print 和 cJSON_PrintUnformatted返回來的字符指針需要free掉內(nè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)行解析,第一種是固定的,寫死的方式;第二種是靈活的的方式解析!
打開文件讀取josn數(shù)據(jù)
// 打開文件 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;
直接通過鍵進(jìn)行解析的
// 解析:"name": "小明", item = cJSON_GetObjectItem(root, "name"); if (item != NULL) { /* 寫法一:*/ // 判斷是不是字符串類型 //if (item->type == cJSON_String) { // v_str = cJSON_Print(item); // 通過函數(shù)獲取值 // printf("name = %s\n", v_str); // free(v_str); // 通過函數(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)體中沒有給出,所以使用字符串代替 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)體中沒有給出,所以使用字符串代替 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); // 可以通過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) { // 再通過類型去區(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 *); // 通過遍歷指針數(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": "漢語", "grade": 10 } while (obj) { if (obj->type == cJSON_Object) { // 獲取到子元素的子元素 cJSON *value = obj->child; // 也就是:{ "language": "漢語", "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); } // 通過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);
只不過得先定位到對(duì)應(yīng)的cJSON指針!
打開文件、讀取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) { // 還是得通過索引去定位到具體需要修改的值 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": "中國象棋", "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("中國象棋")); 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": "漢語", "grade": 10 }, ====> "serialOne": { "language": "粵語", "grade": 9 }, "serialTwo": { "language": "英語", "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("粵語")); 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)); }
修改前:
修改后:
寫入文件
// 打開文件 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ì)象指定鍵即可!
打開文件、讀取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"); // 通過鍵進(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); // 通過索引進(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"); //} }
刪除前:
刪除后:
寫入文件
// 打開文件 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)目,將代碼拷貝過去,再導(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": "漢語", "grade": 10 }, "serialTwo": { "language": "英語", "grade": 6} }, */ // 定義對(duì)象 { } cJSON *serialOne = cJSON_CreateObject(); cJSON_AddItemToObject(serialOne, "language", cJSON_CreateString("漢語")); cJSON_AddItemToObject(serialOne, "grade", cJSON_CreateNumber(10)); cJSON *serialTwo = cJSON_CreateObject(); cJSON_AddItemToObject(serialTwo, "language", cJSON_CreateString("英語")); 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:沒有做格式調(diào)整 // 返回的字符串指針需要自己釋放 free(cPrint); free(cPrintUnformatted); // 打開文件 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 () { // 打開文件 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); // 通過函數(shù)獲取值 // printf("name = %s\n", v_str); // free(v_str); // 通過函數(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)體中沒有給出,所以使用字符串代替 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)體中沒有給出,所以使用字符串代替 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); // 可以通過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) { // 再通過類型去區(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": "漢語", "grade": 10 }, "serialTwo": { "language": "英語", "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 *); // 通過遍歷指針數(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": "漢語", "grade": 10 } while (obj) { if (obj->type == cJSON_Object) { // 獲取到子元素的子元素 cJSON *value = obj->child; // 也就是:{ "language": "漢語", "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); } // 通過next可以自由獲取里面的元素了 value = value->next; } } // 獲得下一組子元素 obj = obj->next; } } } // 使用了cJSON_Parse之后,記得調(diào)用cJSON_Delete函數(shù)釋放 cJSON_Delete(root); } void alterJson() { // 打開文件 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)體中沒有給出,所以使用字符串代替 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); // 可以通過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": "中國象棋", "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("中國象棋")); 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) { // 再通過類型去區(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": "漢語", "grade": 10 }, ====> "serialOne": { "language": "粵語", "grade": 9 }, "serialTwo": { "language": "英語", "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("粵語")); 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": "漢語", "grade": 10 } while (obj) { if (obj->type == cJSON_Object) { // 獲取到子元素的子元素 cJSON *value = obj->child; // 也就是:{ "language": "漢語", "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); } // 通過next可以自由獲取里面的元素了 value = value->next; } } obj = obj->next; } } // 打開文件 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() { // 打開文件 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"); // 通過鍵進(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); // 通過索引進(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"); //} } // 打開文件 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í)挺累的,不過還好,最后還是按照自己意愿寫完了這篇博客!
其中,解析那一個(gè)模塊有兩種解析方式,建議使用第二種解析方式,比較靈活,即使后期再加多了幾個(gè)節(jié)點(diǎn),也照樣可以解析出來,且無需再改動(dòng)代碼!
我個(gè)人感覺,這篇博客對(duì)json的操作,應(yīng)該是很全面的了,幾乎涵蓋了所有的結(jié)果性,現(xiàn)在記錄下來分享給需要的各位!
到此這篇關(guān)于C++使用cjson操作Json格式文件(創(chuàng)建、插入、解析、修改、刪除)的文章就介紹到這了,更多相關(guān)C++使用cjson操作Json內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實(shí)現(xiàn)與Lua相互調(diào)用的示例詳解
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)與Lua相互調(diào)用的方法,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解一下2023-03-03GCC 編譯使用動(dòng)態(tài)鏈接庫和靜態(tài)鏈接庫的方法
根據(jù)鏈接時(shí)期的不同,庫又有靜態(tài)庫和動(dòng)態(tài)庫之分,有別于靜態(tài)庫,動(dòng)態(tài)庫的鏈接是在程序執(zhí)行的時(shí)候被鏈接的2013-03-03c語言程序設(shè)計(jì)文件操作方法示例(CreateFile和fopen)
c主要的文件操作函數(shù)有:CreateFile,CloseHandle,ReadFile,WriteFile,SetFilePointer,GetFileSize。其中的讀寫操作是以字符為單位,獲得文件大小也是以字符為單位。2013-12-12C++實(shí)現(xiàn)約瑟夫環(huán)的循環(huán)單鏈表
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)約瑟夫環(huán)的循環(huán)單鏈表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10