C++ - CJosn的使用
概述
为什么要学习解析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进行存储数据:
1
2
3
4
5
6
7
8
9
10
11
12
|
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类型,与下面的宏进行判断
1
2
3
4
5
6
7
8
|
/* 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进行释放
1
2
3
4
|
extern cJSON *cJSON_Parse( const char *value); // 释放cJSON_Parse返回的指针 extern void cJSON_Delete(cJSON *c); |
cjson指针指针生成字符串的函数
1
2
3
4
|
// 这个生成的字符串有做格式调整 extern char *cJSON_Print(cJSON *item); // 这个没有作格式调整,就是一行字符串显示 extern char *cJSON_PrintUnformatted(cJSON *item); |
使用这个两个函数一定一定一定要释放它们返回的指针内存,否则会造成内存泄漏。
…
其他的就不介绍了,都会在下面中使用到!
三、封装Json
{ }
1
2
3
4
|
"interest" : { "basketball" : "篮球" , "badminton" : "羽毛球" } |
代码实现上述效果:
1
2
3
4
5
6
7
|
// 定义对象 { } cJSON *interest = cJSON_CreateObject(); // 插入元素,对应 键值对 cJSON_AddItemToObject(interest, "basketball" , cJSON_CreateString( "篮球" )); // 当值是字符串时,需要使用函数cJSON_CreateString()创建 cJSON_AddItemToObject(interest, "badminton" , cJSON_CreateString( "羽毛球" )); // 或者使用宏进行添加 //cJSON_AddStringToObject(interest, "badminton", "羽毛球"); // 或者这样写 |
[ ]
1
|
"color" : [ "black" , "white" ] |
代码实现上述效果:
1
2
3
4
5
|
// 定义 [ ] 数组 cJSON *color = cJSON_CreateArray(); // 往数组中添加元素 cJSON_AddItemToArray(color, cJSON_CreateString( "black" )); cJSON_AddItemToArray(color, cJSON_CreateString( "white" )); |
[ { }, { } ]
1
2
3
4
|
"like" : [ { "game" : "马里奥" , "price" : 66.6 }, { "game" : "魂斗罗" , "price" : 77.7 } ] |
代码实现上述效果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
// 定义 { } 对象 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); |
[ [ ], [ ] ]
1
2
3
4
|
"education" : [ [ "小学" , "初中" ], [ "高中" , "大学" ] ] |
代码实现上述效果:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// 定义 [ ] 数组 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); |
{ { }, { } }
1
2
3
4
|
"languages" : { "serialOne" : { "language" : "汉语" , "grade" : 10 }, "serialTwo" : { "language" : "英语" , "grade" : 6} } |
代码实现上述效果:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// 定义对象 { } 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); |
定义根节点 也即是最外层 { }
1
2
|
// 创建跟对象 cJSON *root = cJSON_CreateObject(); |
将上面定义的{ } 与 [ ] 都插入到跟节点{ }中
1
2
3
4
5
6
7
8
9
10
11
12
|
// 将子项插入根项中 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"); // 或者这样写也是可以的 |
打印控制台查看
1
2
3
4
5
6
7
8
|
// 打印控制台查看 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掉内存!
写入文件中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// 打开文件 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指针
1
2
|
// 释放指针内存 cJSON_Delete(root); |
把代码写好后,编译运行,会在自己的项目路径中创建一个JSON文件,并写入内容,文件内容如下:
四、解析Json
解析时需要使用结构体中的type类型进行判断,这是为了安全性考虑!
解析时也可以使用cJSON_Print函数去获取字符串或者使用结构体中的valuestring进行获取,但是要注意的是,使用cJSON_Print函数去获取字符串需要free掉获取到的指针,否则会造成内存泄漏!
下面解析会提供两种方式进行解析,第一种是固定的,写死的方式;第二种是灵活的的方式解析!
打开文件读取josn数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
// 打开文件 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" ); return ; } printf ( "%s\n" , jsonStr); fclose (file); |
使用读取到的json数据初始化cJSON指针
1
2
3
4
5
6
7
8
9
10
|
// 将读取到的json字符串转换成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); |
定义一些下面需要使用到的变量
1
2
3
4
5
|
cJSON *item = NULL; char *v_str = NULL; double v_double = 0.0; int v_int = 0; bool v_bool = false ; |
直接通过键进行解析的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
// 解析:"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; } |
解析对象 { }
也就是解析下图内容:
解析代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
{ /*************** 方式一 ***************/ 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; } } } |
解析数组 [ ]
也就是解析下图内容:
解析代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
{ /*************** 方式一 ***************/ 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; } } } |
解析数组中的对象 [ { } ]
也就是解析下图内容:
解析代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
{ /*************** 方式一 ***************/ 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; } } } |
解析 数组 中 数组 [ [ ] [ ] ]
也就是解析下图内容:
解析代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
{ /*************** 方式一 ***************/ 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; } } } |
解析 对象 中 对象 { { } }
也就是解析下图内容:
解析代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
{ /*************** 方式一 ***************/ 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
修改只是使用到两个函数就可以了:
1
2
|
extern void cJSON_ReplaceItemInArray(cJSON *array, int which,cJSON *newitem); extern void cJSON_ReplaceItemInObject(cJSON *object, const char *string,cJSON *newitem); |
只不过得先定位到对应的cJSON指针!
打开文件、读取json数据,初始化cJSON这些与上面重复
1
2
|
// 将读取到的json字符串转换成json变量指针 cJSON *root = cJSON_Parse(jsonStr); |
定义下面所需要用到的变量
1
2
|
// 这个变量用于接收定位到的cJSON cJSON *item = NULL; |
直接进行接修改的
1
2
3
4
5
6
7
8
9
10
11
12
|
/* "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 )); |
修改前:
修改后:
修改 { } 中的值
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/* "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( "林丹" )); } |
修改前:
修改后:
修改数组 [ ] 中的元素
1
2
3
4
5
6
7
|
/* "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" )); } |
修改前:
修改后:
修改 [ { } ] 中的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/* "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)); } |
修改前:
修改后:
修改 [ [ ] ] 中的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/* "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( "大学大四" )); } |
修改前:
修改后:
修改 { { } } 中的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/* "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)); } |
修改前:
修改后:
写入文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// 打开文件 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指针
1
2
|
// 使用了cJSON_Parse之后,记得调用cJSON_Delete函数释放 cJSON_Delete(root); |
六、删除Json
删除也是只用两个函数即可:
1
2
|
extern void cJSON_DeleteItemFromArray(cJSON *array, int which); extern void cJSON_DeleteItemFromObject(cJSON *object, const char *string); |
找到对应的cJOSN指针后,删除数组指定索引,删除对象指定键即可!
打开文件、读取json数据,初始化cJSON这些与上面重复
1
2
|
// 将读取到的json字符串转换成json变量指针 cJSON *root = cJSON_Parse(jsonStr); |
定义下面所需要用到的变量
1
2
|
// 这个变量用于接收定位到的cJSON cJSON *item = NULL; |
直接进行删除的
1
2
3
|
/* 删除: "name": "小红" */ // 使用这个函数直接进行删除 cJSON_DeleteItemFromObject(root, "name" ); // 通过键进行删除 |
删除 { } 中的值
1
2
3
4
5
6
7
8
9
10
|
/* 删除: "interest": { "badminton": "林丹" } */ item = cJSON_GetObjectItem(root, "interest" ); // 获取到对应的节点对象就可以直接删除了 if (item != NULL) { cJSON_DeleteItemFromObject(item, "badminton" ); } |
删除前:
删除后:
删除数组[ ]中的元素
1
2
3
4
5
6
|
/* 删除: "color": ["blue"] */ item = cJSON_GetObjectItem(root, "color" ); // 获取到对应的节点数组就可以直接删除了 if (item != NULL) { cJSON_DeleteItemFromArray(item, 1); // 通过索引进行删除 } |
删除前:
删除后:
删除 [ ] 中的 { }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/* 删除: "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"); //} } |
删除前:
删除后:
删除 [ ] 中的 [ ]
1
2
3
4
5
6
7
8
9
10
11
|
/* 删除: "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); //} } |
删除前:
删除后:
删除 { } 中的 { }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/* 删除 "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"); //} } |
删除前:
删除后:
写入文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// 打开文件 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指针内存
1
2
|
// 使用了cJSON_Parse之后,记得调用cJSON_Delete函数释放 cJSON_Delete(root); |
七、全部代码
在VS2017及其以上的版本中,新建一个空项目,将代码拷贝过去,再导入cJSON.h 和 cJSON.c 文件即可运行!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
|
#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" ); return ; } printf ( "%s\n" , jsonStr); fclose (file); // 将读取到的json字符串转换成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); // 通过函数获取值 // 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" ); return ; } printf ( "%s\n" , jsonStr); fclose (file); // 将读取到的json字符串转换成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可以直接进行修改 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" ); return ; } printf ( "%s\n" , jsonStr); fclose (file); // 将读取到的json字符串转换成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": "小红" */ // 使用这个函数直接进行删除 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的操作,应该是很全面的了,几乎涵盖了所有的结果性,现在记录下来分享给需要的各位!
==============================
原文链接:
https://www.jb51.net/article/236576.htm
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix