为什么要学习解析Json文件?
工作需要呗!
最近在工作项目中,有需求是需要进行解析Json字符串的,但是我只会使用QT去解析Json,且主管规定要使用C/C++语言去解析,说是为了方便移植到其他项目中进行使用…
没办法,只能硬着头皮,在网上找找有没有什么解析Json的开源库是C/C++可以使用的。
找了许多,网上也提供了许多,最终我选择了cJOSN,不为什么,就是因为它小巧玲珑,且是纯C的!
花了一两周的悠闲时间去学习,把一些比较常用的解析的JSON字符串解析解析记录下来!
最后简单介绍一下json是什么吧:
json是一个轻量级的数据存储交换语言,其是通过键值对的形式存储的,例如:{ “key” : “value” }
注意:键需要使用双引号括起来,值如果是字符串也需要使用双引号括起来,其他类型不需要。
json主要用来网络数据传输!
一、准备cJSON开源库
cjosn库下载网址:https://sourceforge.net/projects/cjson/
下载后会得到一个压缩包,解压后进入里面拷贝cJSON.c和cJSON.h文件到自己的项目中去。
最后在自己的项目中把这两个文件添加进来即可!
Linux 和 Window下都可以使用!
二、cJSON介绍
-
首先介绍一下json数据:
上图的json数据就是这篇博客将要操作的,将会对其进行创建、解析、修改、删除操作。
其中这里包含项目中常用的封装和解析。 -
cJSON主要是通过结构体cJSON进行存储数据:
typedef struct cJSON { struct cJSON *next,*prev; /* next是获取下一个元素数据,prev是获取前一个元素数据 */ struct cJSON *child; /* 获取第一个元素数据,当需要获取下一个时,就得使用next了. */ int type; /* 当前的json类型对象、数组、字符串、数字、null、true、false等 */ char *valuestring; /* 字符串值, if type==cJSON_String */ int valueint; /* 整形类型值, if type==cJSON_Number */ double valuedouble; /* 浮点数类型值, if type==cJSON_Number */ char *string; /* 这个是键 */ } cJSON;
-
type类型,与下面的宏进行判断
/* cJSON Types: */ #define cJSON_False 0 // true #define cJSON_True 1 // false #define cJSON_NULL 2 // NULL #define cJSON_Number 3 // 数字 #define cJSON_String 4 // 字符串 #define cJSON_Array 5 // 数组 #define cJSON_Object 6 // 对象
-
字符串生成cjson指针的函数,使用后需要调用cJSON_Delete进行释放
extern cJSON *cJSON_Parse(const char *value); // 释放cJSON_Parse返回的指针 extern void cJSON_Delete(cJSON *c);
-
cjson指针指针生成字符串的函数
// 这个生成的字符串有做格式调整 extern char *cJSON_Print(cJSON *item); // 这个没有作格式调整,就是一行字符串显示 extern char *cJSON_PrintUnformatted(cJSON *item);
使用这个两个函数一定一定一定要释放它们返回的指针内存,否则会造成内存泄漏。
…
其他的就不介绍了,都会在下面中使用到!
三、封装Json
-
{ }
"interest": { "basketball": "篮球", "badminton": "羽毛球" }
代码实现上述效果:
// 定义对象 { } cJSON *interest = cJSON_CreateObject(); // 插入元素,对应 键值对 cJSON_AddItemToObject(interest, "basketball", cJSON_CreateString("篮球")); // 当值是字符串时,需要使用函数cJSON_CreateString()创建 cJSON_AddItemToObject(interest, "badminton", cJSON_CreateString("羽毛球")); // 或者使用宏进行添加 //cJSON_AddStringToObject(interest, "badminton", "羽毛球"); // 或者这样写
-
[ ]
"color": [ "black", "white"]
代码实现上述效果:
// 定义 [ ] 数组 cJSON *color = cJSON_CreateArray(); // 往数组中添加元素 cJSON_AddItemToArray(color, cJSON_CreateString("black")); cJSON_AddItemToArray(color, cJSON_CreateString("white"));
-
[ { }, { } ]
"like": [ { "game": "马里奥", "price": 66.6 }, { "game": "魂斗罗", "price": 77.7 } ]
代码实现上述效果:
// 定义 { } 对象 cJSON *likeObject1 = cJSON_CreateObject(); cJSON_AddItemToObject(likeObject1, "game", cJSON_CreateString("马里奥")); cJSON_AddItemToObject(likeObject1, "price", cJSON_CreateNumber(66.6)); // 当值是数字时,需要使用函数cJSON_CreateNumber()创建 //cJSON_AddNumberToObject(likeObject1, "price", 66.6); // 或者这样写 cJSON *likeObject2 = cJSON_CreateObject(); cJSON_AddItemToObject(likeObject2, "game", cJSON_CreateString("魂斗罗")); cJSON_AddItemToObject(likeObject2, "price", cJSON_CreateNumber(77.7)); // 定义 [ ] 数组 cJSON *like = cJSON_CreateArray(); // 往数组中添加元素 cJSON_AddItemToArray(like, likeObject1); cJSON_AddItemToArray(like, likeObject2);
-
[ [ ], [ ] ]
"education": [ [ "小学", "初中" ], [ "高中", "大学" ] ]
代码实现上述效果:
// 定义 [ ] 数组 cJSON *education1 = cJSON_CreateArray(); cJSON_AddItemToArray(education1, cJSON_CreateString("小学")); cJSON_AddItemToArray(education1, cJSON_CreateString("初中")); cJSON *education2 = cJSON_CreateArray(); cJSON_AddItemToArray(education2, cJSON_CreateString("高中")); cJSON_AddItemToArray(education2, cJSON_CreateString("大学")); // 定义 [ ] 数组 cJSON *education = cJSON_CreateArray(); cJSON_AddItemToArray(education, education1); cJSON_AddItemToArray(education, education2);
-
{ { }, { } }
"languages": { "serialOne": { "language": "汉语", "grade": 10 }, "serialTwo": { "language": "英语", "grade": 6} }
代码实现上述效果:
// 定义对象 { } 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)); // 定义对象 { } cJSON *languages = cJSON_CreateObject(); cJSON_AddItemToObject(languages, "serialOne", serialOne); cJSON_AddItemToObject(languages, "serialTwo", serialTwo);
-
定义根节点 也即是最外层 { }
// 创建跟对象 cJSON *root = cJSON_CreateObject();
-
将上面定义的{ } 与 [ ] 都插入到跟节点{ }中
// 将子项插入根项中 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 插入布尔类型数据需要使用cJSON_CreateBool函数 cJSON_AddItemToObject(root, "address", cJSON_CreateNull()); // "address": null 插入NULL值需要使用cJSON_CreateNull函数 //cJSON_AddTrueToObject(root, "vip"); //cJSON_AddNullToObject(root, "address"); // 或者这样写也是可以的
-
打印控制台查看
// 打印控制台查看 char *cPrint = cJSON_Print(root); char *cPrintUnformatted = cJSON_PrintUnformatted(root); printf("cJSON_Print:\n%s\n", cPrint); // cJSON_Print:有做格式调整 printf("cJSON_PrintUnformatted:\n%s\n", cPrintUnformatted); // cJSON_PrintUnformatted:没有做格式调整 // 返回的字符串指针需要自己释放 free(cPrint); free(cPrintUnformatted);
记得使用cJSON_Print 和 cJSON_PrintUnformatted返回来的字符指针需要free掉内存!
-
写入文件中
// 打开文件 FILE *file = NULL; file = fopen(FILE_NAME, "w"); // FILE_NAME ==> "jss.json" if (file == NULL) { printf("Open file fail!\n"); // 释放指针内存 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指针
// 释放指针内存 cJSON_Delete(root);
-
把代码写好后,编译运行,会在自己的项目路径中创建一个JSON文件,并写入内容,文件内容如下:
四、解析Json
解析时需要使用结构体中的type类型进行判断,这是为了安全性考虑!
解析时也可以使用cJSON_Print函数去获取字符串或者使用结构体中的valuestring进行获取,但是要注意的是,使用cJSON_Print函数去获取字符串需要free掉获取到的指针,否则会造成内存泄漏!
下面解析会提供两种方式进行解析,第一种是固定的,写死的方式;第二种是灵活的的方式解析!
-
打开文件读取josn数据
// 打开文件 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); // 分配符合文件大小的内存 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"); fclose(file); return; } printf("%s\n", jsonStr); fclose(file);
-
使用读取到的json数据初始化cJSON指针
// 将读取到的json字符串转换成json变量指针 cJSON *root = cJSON_Parse(jsonStr); if (!root) { printf("Error before: [%s]\n", cJSON_GetErrorPtr()); 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); // 通过函数获取值 // printf("name = %s\n", v_str); // free(v_str); // 通过函数返回的指针需要自行free,否则会导致内存泄漏 // v_str = NULL; //} /* 写法二: */ // 判断是不是字符串类型 if (item->type == cJSON_String) { v_str = item->valuestring; // 此赋值是浅拷贝,不需要现在释放内存 printf("name = %s\n", v_str); } } // 解析:"age": "23", item = cJSON_GetObjectItem(root, "age"); if (item != NULL) { // 合法性检查 if (item->type == cJSON_Number) { // 判断是不是数字 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类型结构体中没有给出,所以使用字符串代替 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类型结构体中没有给出,所以使用字符串代替 printf("address = %s\n", v_str); free(v_str); v_str = NULL; }
-
解析对象 { }
也就是解析下图内容:解析代码:
{ /*************** 方式一 ***************/ item = cJSON_GetObjectItem(root, "interest"); // 获取object对象名 if (item != NULL) { cJSON *val = NULL; val = cJSON_GetObjectItem(item, "basketball"); // 根据object对象名获得里面的basketball数据 if (val != NULL && val->type == cJSON_String) { v_str = val->valuestring; printf("basketball = %s\n", v_str); } val = cJSON_GetObjectItem(item, "badminton"); // 根据object对象名获得里面的badminton数据 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获得键 } // 获取下一个元素 obj = obj->next; } } }
-
解析数组 [ ]
也就是解析下图内容:
解析代码:{ /*************** 方式一 ***************/ item = cJSON_GetObjectItem(root, "color"); if (item != NULL) { int size = cJSON_GetArraySize(item); // 获得数组个数 for (int i = 0; i < size; i++) { cJSON *arr = cJSON_GetArrayItem(item, i); // 根据索引获得数组中的值 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); } // 获取下一个元素 arr = arr->next; } } }
-
解析数组中的对象 [ { } ]
也就是解析下图内容:
解析代码:{ /*************** 方式一 ***************/ item = cJSON_GetObjectItem(root, "like"); if (item != NULL) { int size = cJSON_GetArraySize(item); // 获取的数组大小 for (int i = 0; i < size; i++) { cJSON *obj = cJSON_GetArrayItem(item, i); // 获取的数组里的obj cJSON *val = NULL; if (obj != NULL && obj->type == cJSON_Object) { // 判断数字内的元素是不是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) { // 再通过类型去区分 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); } // 获取下一个元素 objValue = objValue->next; } } // 获取下一组元素 obj = obj->next; } } }
-
解析 数组 中 数组 [ [ ] [ ] ]
也就是解析下图内容:
解析代码:{ /*************** 方式一 ***************/ item = cJSON_GetObjectItem(root, "education"); if (item != NULL) { int size = cJSON_GetArraySize(item); // 获取的数组大小 for (int i = 0; i < size; i++) { cJSON *arr = cJSON_GetArrayItem(item, i); // 解析获得 [ "小学", "初中" ] 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); // 再进一步解析就可以得到数组里面的元素了 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; // 获得 [ "小学", "初中" ] while (arr) { if (arr->type == cJSON_Array) { cJSON *arrValue = arr->child; // 获得 "小学" while (arrValue) { if (arrValue->type == cJSON_String) { char *v_str = arrValue->valuestring; printf("education = %s\n", v_str); } arrValue = arrValue->next; // 获取下一个元素 } } // 获取下一组 arr = arr->next; } } }
-
解析 对象 中 对象 { { } }
也就是解析下图内容:
解析代码:{ /*************** 方式一 ***************/ char *arrStr[] = { "serialOne", "serialTwo" }; // 可以提前定义需要解析的对象键,这样就可以使用for循环进行解析了 item = cJSON_GetObjectItem(root, "languages"); if (item != NULL) { cJSON *val = NULL; int size = sizeof(arrStr) / sizeof(char *); // 通过遍历指针数组,获得每个对象的键,在进行解析操作(如果不使用for循环解析,那就老老实实的写代码将全部个数解析完毕) 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里的第一个子元素 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; } } }
-
解析结果如下:
因为有两种解析方式,所以他们都打印了两遍!
五、修改Json
修改只是使用到两个函数就可以了:
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
只不过得先定位到对应的cJSON指针!
-
打开文件、读取json数据,初始化cJSON这些与上面重复
// 将读取到的json字符串转换成json变量指针 cJSON *root = cJSON_Parse(jsonStr);
-
定义下面所需要用到的变量
// 这个变量用于接收定位到的cJSON cJSON *item = NULL;
-
直接进行接修改的
/* "name": "小明" ====> "name": "小红" */ // 使用cJSON_ReplaceItemInObject可以直接进行修改 cJSON_ReplaceItemInObject(root, "name", cJSON_CreateString("小红")); /* "age": 23 ====> "age": 20 */ cJSON_ReplaceItemInObject(root, "age", cJSON_CreateNumber(20)); /* "vip": true ====> "vip": false */ // 使用cJSON_ReplaceItemInObject可以直接进行修改 cJSON_ReplaceItemInObject(root, "vip", cJSON_CreateBool(false));
修改前:
修改后:
-
修改 { } 中的值
/* "interest": { 修改后: "interest": { "basketball": "篮球", ====> "basketball": "姚明", "badminton": "羽毛球" "badminton": "林丹" } } */ // 首先获取到需要修改的指针 item = cJSON_GetObjectItem(root, "interest"); if (item != NULL) { // 使用cJSON_ReplaceItemInObject可以直接进行修改 cJSON_ReplaceItemInObject(item, "basketball", cJSON_CreateString("姚明")); cJSON_ReplaceItemInObject(item, "badminton", cJSON_CreateString("林丹")); }
修改前:
修改后:
-
修改数组 [ ] 中的元素
/* "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); // 根据索引获得数组中的值 cJSON_ReplaceItemInObject(arrObj, "game", cJSON_CreateString("炸弹人")); cJSON_ReplaceItemInObject(arrObj, "price", cJSON_CreateNumber(88.8)); arrObj = cJSON_GetArrayItem(item, 1); // 根据索引获得数组中的值 cJSON_ReplaceItemInObject(arrObj, "game", cJSON_CreateString("中国象棋")); cJSON_ReplaceItemInObject(arrObj, "price", cJSON_CreateNumber(99.9)); }
修改前:
修改后:
-
修改 [ [ ] ] 中的值
/* "education": [ 修改后: "education": [ [ "小学", "初中" ], ====> [ "小学六年级", "初中初三" ], [ "高中", "大学" ] [ "高中高三", "大学大四" ] ], ], */ item = cJSON_GetObjectItem(root, "education"); if (item != NULL) { cJSON *arrArr = NULL; arrArr = cJSON_GetArrayItem(item, 0); // 根据索引获得数组中的值 cJSON_ReplaceItemInArray(arrArr, 0, cJSON_CreateString("小学六年级")); cJSON_ReplaceItemInArray(arrArr, 1, cJSON_CreateString("初中初三")); arrArr = cJSON_GetArrayItem(item, 1); // 根据索引获得数组中的值 cJSON_ReplaceItemInArray(arrArr, 0, cJSON_CreateString("高中高三")); cJSON_ReplaceItemInArray(arrArr, 1, cJSON_CreateString("大学大四")); }
修改前:
修改后:
-
修改 { { } } 中的值
/* "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可以直接进行修改 cJSON_ReplaceItemInObject(obj, "language", cJSON_CreateString("粤语")); cJSON_ReplaceItemInObject(obj, "grade", cJSON_CreateNumber(9)); obj = cJSON_GetObjectItem(item, "serialTwo"); // 使用cJSON_ReplaceItemInObject可以直接进行修改 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"); // 释放指针内存 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之后,记得调用cJSON_Delete函数释放 cJSON_Delete(root);
六、删除Json
删除也是只用两个函数即可:
extern void cJSON_DeleteItemFromArray(cJSON *array,int which);
extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string);
找到对应的cJOSN指针后,删除数组指定索引,删除对象指定键即可!
-
打开文件、读取json数据,初始化cJSON这些与上面重复
// 将读取到的json字符串转换成json变量指针 cJSON *root = cJSON_Parse(jsonStr);
-
定义下面所需要用到的变量
// 这个变量用于接收定位到的cJSON cJSON *item = NULL;
-
直接进行删除的
/* 删除: "name": "小红" */ // 使用这个函数直接进行删除 cJSON_DeleteItemFromObject(root, "name"); // 通过键进行删除
-
删除 { } 中的值
/* 删除: "interest": { "badminton": "林丹" } */ item = cJSON_GetObjectItem(root, "interest"); // 获取到对应的节点对象就可以直接删除了 if (item != NULL) { cJSON_DeleteItemFromObject(item, "badminton"); }
删除前:
删除后:
-
删除数组[ ]中的元素
/* 删除: "color": ["blue"] */ item = cJSON_GetObjectItem(root, "color"); // 获取到对应的节点数组就可以直接删除了 if (item != NULL) { cJSON_DeleteItemFromArray(item, 1); // 通过索引进行删除 }
删除前:
删除后:
-
删除 [ ] 中的 { }
/* 删除: "like": [ { "game": "炸弹人", "price": 88.800000 }, ] */ item = cJSON_GetObjectItem(root, "like"); if (item != NULL) { cJSON_DeleteItemFromArray(item, 0); 还可以再继续深入进行删除 //cJSON *arrObj = cJSON_GetArrayItem(item, 0); // 根据索引获得数组中的值 //if (arrObj != NULL) { // cJSON_DeleteItemFromObject(arrObj, "price"); //} }
删除前:
删除后:
-
删除 [ ] 中的 [ ]
/* 删除: "education": [["高中高三", "大学大四"]] */ item = cJSON_GetObjectItem(root, "education"); if (item != NULL) { cJSON_DeleteItemFromArray(item, 1); 还可以再继续深入进行删除 //cJSON *arrArr = cJSON_GetArrayItem(item, 0); // 根据索引获得数组中的值 //if (arrArr != NULL) { // cJSON_DeleteItemFromArray(arrArr, 1); //} }
删除前:
删除后:
-
删除 { } 中的 { }
/* 删除 "languages": { "serialTwo": { "language":"白话", "grade":8 } } */ item = cJSON_GetObjectItem(root, "languages"); if (item != NULL) { cJSON_DeleteItemFromObject(item, "serialTwo"); 还可以再继续深入进行删除 //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"); // 释放指针内存 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指针内存
// 使用了cJSON_Parse之后,记得调用cJSON_Delete函数释放 cJSON_Delete(root);
七、全部代码
在VS2017及其以上的版本中,新建一个空项目,将代码拷贝过去,再导入cJSON.h 和 cJSON.c 文件即可运行!
#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": "羽毛球"
},
*/
// 定义对象 { }
cJSON *interest = cJSON_CreateObject();
// 插入元素,对应 键值对
cJSON_AddItemToObject(interest, "basketball", cJSON_CreateString("篮球")); // 当值是字符串时,需要使用函数cJSON_CreateString()创建
cJSON_AddItemToObject(interest, "badminton", cJSON_CreateString("羽毛球"));
//cJSON_AddStringToObject(interest, "badminton", "羽毛球"); // 或者这样写
/*
"color": [ "black", "white" ],
*/
// 定义 [ ] 数组
cJSON *color = cJSON_CreateArray();
// 往数组中添加元素
cJSON_AddItemToArray(color, cJSON_CreateString("black"));
cJSON_AddItemToArray(color, cJSON_CreateString("white"));
/*
"like": [
{ "game": "马里奥", "price": 66.6 },
{ "game": "魂斗罗", "price": 77.7 }
],
*/
// 定义 { } 对象
cJSON *likeObject1 = cJSON_CreateObject();
cJSON_AddItemToObject(likeObject1, "game", cJSON_CreateString("马里奥"));
cJSON_AddItemToObject(likeObject1, "price", cJSON_CreateNumber(66.6)); // 当值是数字时,需要使用函数cJSON_CreateNumber()创建
//cJSON_AddNumberToObject(likeObject1, "price", 66.6); // 或者这样写
cJSON *likeObject2 = cJSON_CreateObject();
cJSON_AddItemToObject(likeObject2, "game", cJSON_CreateString("魂斗罗"));
cJSON_AddItemToObject(likeObject2, "price", cJSON_CreateNumber(77.7));
// 定义 [ ] 数组
cJSON *like = cJSON_CreateArray();
// 往数组中添加元素
cJSON_AddItemToArray(like, likeObject1);
cJSON_AddItemToArray(like, likeObject2);
/*
"education": [
[ "小学", "初中" ],
[ "高中", "大学" ]
],
*/
// 定义 [ ] 数组
cJSON *education1 = cJSON_CreateArray();
cJSON_AddItemToArray(education1, cJSON_CreateString("小学"));
cJSON_AddItemToArray(education1, cJSON_CreateString("初中"));
cJSON *education2 = cJSON_CreateArray();
cJSON_AddItemToArray(education2, cJSON_CreateString("高中"));
cJSON_AddItemToArray(education2, cJSON_CreateString("大学"));
// 定义 [ ] 数组
cJSON *education = cJSON_CreateArray();
cJSON_AddItemToArray(education, education1);
cJSON_AddItemToArray(education, education2);
/*
"languages": {
"serialOne": { "language": "汉语", "grade": 10 },
"serialTwo": { "language": "英语", "grade": 6}
},
*/
// 定义对象 { }
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));
// 定义对象 { }
cJSON *languages = cJSON_CreateObject();
cJSON_AddItemToObject(languages, "serialOne", serialOne);
cJSON_AddItemToObject(languages, "serialTwo", serialTwo);
// 创建跟对象
cJSON *root = cJSON_CreateObject();
// 将子项插入根项中
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 插入布尔类型数据需要使用cJSON_CreateBool函数
cJSON_AddItemToObject(root, "address", cJSON_CreateNull()); // "address": null 插入NULL值需要使用cJSON_CreateNull函数
//cJSON_AddTrueToObject(root, "vip");
//cJSON_AddNullToObject(root, "address"); // 或者这样写也是可以的
// 打印控制台查看
char *cPrint = cJSON_Print(root);
char *cPrintUnformatted = cJSON_PrintUnformatted(root);
printf("cJSON_Print:\n%s\n\n\n", cPrint); // cJSON_Print:有做格式调整
printf("cJSON_PrintUnformatted:\n%s\n\n\n", cPrintUnformatted); // cJSON_PrintUnformatted:没有做格式调整
// 返回的字符串指针需要自己释放
free(cPrint);
free(cPrintUnformatted);
// 打开文件
FILE *file = NULL;
file = fopen(FILE_NAME, "w"); // FILE_NAME ==> "jss.json"
if (file == NULL) {
printf("Open file fail!\n");
// 释放指针内存
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_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);
// 分配符合文件大小的内存
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");
fclose(file);
return;
}
printf("%s\n", jsonStr);
fclose(file);
// 将读取到的json字符串转换成json变量指针
cJSON *root = cJSON_Parse(jsonStr);
if (!root) {
printf("Error before: [%s]\n", cJSON_GetErrorPtr());
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); // 通过函数获取值
// printf("name = %s\n", v_str);
// free(v_str); // 通过函数返回的指针需要自行free,否则会导致内存泄漏
// v_str = NULL;
//}
/* 写法二: */
// 判断是不是字符串类型
if (item->type == cJSON_String) {
v_str = item->valuestring; // 此赋值是浅拷贝,不需要现在释放内存
printf("name = %s\n", v_str);
}
}
// 解析:"age": "23",
item = cJSON_GetObjectItem(root, "age");
if (item != NULL) { // 合法性检查
if (item->type == cJSON_Number) { // 判断是不是数字
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类型结构体中没有给出,所以使用字符串代替
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类型结构体中没有给出,所以使用字符串代替
printf("address = %s\n", v_str);
free(v_str);
v_str = NULL;
}
/* 解析:
"interest": {
"basketball": "篮球",
"badminton": "羽毛球"
},
*/
{
/*************** 方式一 ***************/
item = cJSON_GetObjectItem(root, "interest"); // 获取object对象名
if (item != NULL) {
cJSON *val = NULL;
val = cJSON_GetObjectItem(item, "basketball"); // 根据object对象名获得里面的basketball数据
if (val != NULL && val->type == cJSON_String) {
v_str = val->valuestring;
printf("basketball = %s\n", v_str);
}
val = cJSON_GetObjectItem(item, "badminton"); // 根据object对象名获得里面的badminton数据
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获得键
}
// 获取下一个元素
obj = obj->next;
}
}
}
/* 解析:
"color": ["black", "white"],
*/
{
/*************** 方式一 ***************/
item = cJSON_GetObjectItem(root, "color");
if (item != NULL) {
int size = cJSON_GetArraySize(item); // 获得数组个数
for (int i = 0; i < size; i++) {
cJSON *arr = cJSON_GetArrayItem(item, i); // 根据索引获得数组中的值
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);
}
// 获取下一个元素
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); // 获取的数组大小
for (int i = 0; i < size; i++) {
cJSON *obj = cJSON_GetArrayItem(item, i); // 获取的数组里的obj
cJSON *val = NULL;
if (obj != NULL && obj->type == cJSON_Object) { // 判断数字内的元素是不是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) {
// 再通过类型去区分
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);
}
// 获取下一个元素
objValue = objValue->next;
}
}
// 获取下一组元素
obj = obj->next;
}
}
}
/*
"education": [
[ "小学", "初中" ],
[ "高中", "大学" ]
],
*/
{
/*************** 方式一 ***************/
item = cJSON_GetObjectItem(root, "education");
if (item != NULL) {
int size = cJSON_GetArraySize(item); // 获取的数组大小
for (int i = 0; i < size; i++) {
cJSON *arr = cJSON_GetArrayItem(item, i); // 解析获得 [ "小学", "初中" ]
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); // 再进一步解析就可以得到数组里面的元素了
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; // 获得 [ "小学", "初中" ]
while (arr) {
if (arr->type == cJSON_Array) {
cJSON *arrValue = arr->child; // 获得 "小学"
while (arrValue) {
if (arrValue->type == cJSON_String) {
char *v_str = arrValue->valuestring;
printf("education = %s\n", v_str);
}
arrValue = arrValue->next; // 获取下一个元素
}
}
// 获取下一组
arr = arr->next;
}
}
}
/*
"languages": {
"serialOne": { "language": "汉语", "grade": 10 },
"serialTwo": { "language": "英语", "grade": 6}
},
*/
{
/*************** 方式一 ***************/
char *arrStr[] = { "serialOne", "serialTwo" }; // 可以提前定义需要解析的对象键,这样就可以使用for循环进行解析了
item = cJSON_GetObjectItem(root, "languages");
if (item != NULL) {
cJSON *val = NULL;
int size = sizeof(arrStr) / sizeof(char *);
// 通过遍历指针数组,获得每个对象的键,在进行解析操作(如果不使用for循环解析,那就老老实实的写代码将全部个数解析完毕)
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里的第一个子元素
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之后,记得调用cJSON_Delete函数释放
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);
// 分配符合文件大小的内存
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");
fclose(file);
return;
}
printf("%s\n", jsonStr);
fclose(file);
// 将读取到的json字符串转换成json变量指针
cJSON *root = cJSON_Parse(jsonStr);
if (!root) {
printf("Error before: [%s]\n", cJSON_GetErrorPtr());
free(jsonStr);
return;
}
free(jsonStr);
cJSON *item = NULL;
/* "name": "小明" ====> "name": "小红" */
// 使用cJSON_ReplaceItemInObject可以直接进行修改
cJSON_ReplaceItemInObject(root, "name", cJSON_CreateString("小红"));
// 解析打印查看是否修改成功
item = cJSON_GetObjectItem(root, "name");
if (item != NULL) {
// 判断是不是字符串类型
if (item->type == cJSON_String) {
char *v_str = item->valuestring; // 此赋值是浅拷贝,不需要现在释放内存
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可以直接进行修改
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类型结构体中没有给出,所以使用字符串代替
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可以直接进行修改
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获得键
}
// 获取下一个元素
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);
}
// 获取下一个元素
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); // 根据索引获得数组中的值
cJSON_ReplaceItemInObject(arrObj, "game", cJSON_CreateString("炸弹人"));
cJSON_ReplaceItemInObject(arrObj, "price", cJSON_CreateNumber(88.8));
arrObj = cJSON_GetArrayItem(item, 1); // 根据索引获得数组中的值
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) {
// 再通过类型去区分
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);
}
// 获取下一个元素
objValue = objValue->next;
}
}
// 获取下一组元素
obj = obj->next;
}
}
/*
"education": [ 修改后: "education": [
[ "小学", "初中" ], ====> [ "小学六年级", "初中初三" ],
[ "高中", "大学" ] [ "高中高三", "大学大四" ]
], ],
*/
item = cJSON_GetObjectItem(root, "education");
if (item != NULL) {
cJSON *arrArr = NULL;
arrArr = cJSON_GetArrayItem(item, 0); // 根据索引获得数组中的值
cJSON_ReplaceItemInArray(arrArr, 0, cJSON_CreateString("小学六年级"));
cJSON_ReplaceItemInArray(arrArr, 1, cJSON_CreateString("初中初三"));
arrArr = cJSON_GetArrayItem(item, 1); // 根据索引获得数组中的值
cJSON_ReplaceItemInArray(arrArr, 0, cJSON_CreateString("高中高三"));
cJSON_ReplaceItemInArray(arrArr, 1, cJSON_CreateString("大学大四"));
}
// 解析打印查看是否修改成功
item = cJSON_GetObjectItem(root, "education");
if (item != NULL) {
cJSON *arr = item->child; // 获得 [ "小学", "初中" ]
while (arr) {
if (arr->type == cJSON_Array) {
cJSON *arrValue = arr->child; // 获得 "小学"
while (arrValue) {
if (arrValue->type == cJSON_String) {
char *v_str = arrValue->valuestring;
printf("education = %s\n", v_str);
}
arrValue = arrValue->next; // 获取下一个元素
}
}
// 获取下一组
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可以直接进行修改
cJSON_ReplaceItemInObject(obj, "language", cJSON_CreateString("粤语"));
cJSON_ReplaceItemInObject(obj, "grade", cJSON_CreateNumber(9));
obj = cJSON_GetObjectItem(item, "serialTwo");
// 使用cJSON_ReplaceItemInObject可以直接进行修改
cJSON_ReplaceItemInObject(obj, "language", cJSON_CreateString("白话"));
cJSON_ReplaceItemInObject(obj, "grade", cJSON_CreateNumber(8));
}
// 解析打印查看是否修改成功
item = cJSON_GetObjectItem(root, "languages");
if (item != NULL) {
// 获取到languages里的第一个子元素
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");
// 释放指针内存
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之后,记得调用cJSON_Delete函数释放
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);
// 分配符合文件大小的内存
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");
fclose(file);
return;
}
printf("%s\n", jsonStr);
fclose(file);
// 将读取到的json字符串转换成json变量指针
cJSON *root = cJSON_Parse(jsonStr);
if (!root) {
printf("Error before: [%s]\n", cJSON_GetErrorPtr());
free(jsonStr);
return;
}
free(jsonStr);
cJSON *item = NULL;
/* 删除: "name": "小红" */
// 使用这个函数直接进行删除
cJSON_DeleteItemFromObject(root, "name"); // 通过键进行删除
/* 删除:
"interest": {
"badminton": "林丹"
}
*/
item = cJSON_GetObjectItem(root, "interest");
// 获取到对应的节点对象就可以直接删除了
if (item != NULL) {
cJSON_DeleteItemFromObject(item, "badminton");
}
/* 删除: "color": ["blue"] */
item = cJSON_GetObjectItem(root, "color");
// 获取到对应的节点数组就可以直接删除了
if (item != NULL) {
cJSON_DeleteItemFromArray(item, 1); // 通过索引进行删除
}
/* 删除:
"like": [
{ "game": "炸弹人", "price": 88.800000 },
]
*/
item = cJSON_GetObjectItem(root, "like");
if (item != NULL) {
cJSON_DeleteItemFromArray(item, 0);
还可以再继续深入进行删除
//cJSON *arrObj = cJSON_GetArrayItem(item, 0); // 根据索引获得数组中的值
//if (arrObj != NULL) {
// cJSON_DeleteItemFromObject(arrObj, "price");
//}
}
/* 删除: "education": [["高中高三", "大学大四"]] */
item = cJSON_GetObjectItem(root, "education");
if (item != NULL) {
cJSON_DeleteItemFromArray(item, 1);
还可以再继续深入进行删除
//cJSON *arrArr = cJSON_GetArrayItem(item, 0); // 根据索引获得数组中的值
//if (arrArr != NULL) {
// cJSON_DeleteItemFromArray(arrArr, 1);
//}
}
/* 删除
"languages": {
"serialTwo": { "language":"白话", "grade":8 }
}
*/
item = cJSON_GetObjectItem(root, "languages");
if (item != NULL) {
cJSON_DeleteItemFromObject(item, "serialTwo");
还可以再继续深入进行删除
//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");
// 释放指针内存
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之后,记得调用cJSON_Delete函数释放
cJSON_Delete(root);
}
八、总结
写这篇博客花了我好多好多好多时间,也确实挺累的,不过还好,最后还是按照自己意愿写完了这篇博客!
其中,解析那一个模块有两种解析方式,建议使用第二种解析方式,比较灵活,即使后期再加多了几个节点,也照样可以解析出来,且无需再改动代码!
我个人感觉,这篇博客对json的操作,应该是很全面的了,几乎涵盖了所有的结果性,现在记录下来分享给需要的各位!