cJSON学习总结
cJSON是什么
cJSON git网站:https://github.com/DaveGamble/cJSON.
json 官网:http://www.json.org
json文件的格式
下面是一个简单但覆盖了大多常用格式的json文件。后面会围绕它做简单的格式介绍。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | { "name": "guoweilkd", "age": 18, "high": 166.9, "married": false, "relation": { "love": { "name": "noName", "loveTime": 6, "age": 19 }, "interest": [ "篮球", 66.666, 19, true, { "name": "noName", "loveTime": 6, "age": 19 } ] } } |
由上面的json文件我们可以看到:
- 它的所有内容由一个
{} 包了起来。我们称它为root对象 。 - 整个json文件可以看成由
对象 ,数组 ,键值对 三种元素的各种嵌套组成。键值对 使用"name":value 的格式。其中value 可以是下面的几种元素:- bool类型:
true ,false .如"married":false 。 - 数值:可以是浮点值或整型值。如
"high":166.9 ,"age":18 ,"tmp":2E-3 . - 字符串:如
"name":"noName" 。 - 对象:如
"relation":{} 。 - 数组:如
"interest":[] 。
- bool类型:
对象 使用{} 作为一个整体。数组 使用[] 作为一个整体。数组中的内容可以是下面几种元素的任意组合:- 对象:
[{...},{...}] 。 - 键值对的
value :如字符串,bool类型等。详见键值对value 的描述。
- 对象:
- 各个元素之间使用
, 分割。 - 注意事项:JSON规范不支持注释。JSON规范之所以不允许加注释,主要是防止过多的注释,影响了文件本身的数据载体的目的。但是后续的JSON5等也支持
// ,/* */ 的注释。
cJSON解析库的使用
对cJSON库最简单的使用是只包含
在谈cJSON库接口时,我们必须要先了解结构体
1 2 3 4 5 6 7 8 9 10 | typedef struct cJSON{ struct cJSON *next;//兄弟指针,指向后一个节点 struct cJSON *prev;//兄弟指针,指向前一个节点 struct cJSON *child;//儿子节点,指向子对象/数组 int type; //键值对中value值的类型。见键值对的描述 char *valuestring; //如果type为字符串flag,则此处为value的字符串值 int valueint; //如果type为数值flag,则此处为value的整型值 double valuedouble; //如果type为数值flag,则此处为value的浮点型值 char *string; //键值对的name名称。 } cJSON; |
使用cJSON库生成json文件
此程序生成的json文件为上面列举的json文件。可以对照学习。
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 | #include <stdio.h> #include <stdlib.h> #include "cJSON.h" #include "string.h" int main(void) { char *cjson_str = NULL; cJSON *root = cJSON_CreateObject(); cJSON *relation = cJSON_CreateObject(); cJSON *love = cJSON_CreateObject(); cJSON *friend = cJSON_CreateObject(); cJSON *interest = cJSON_CreateArray(); /* 根节点下添加元素 */ cJSON_AddItemToObject(root, "name", cJSON_CreateString("guoweilkd"));//在对象中插入字符串 cJSON_AddItemToObject(root, "age", cJSON_CreateNumber(18)); //在对象中插入整型数值 cJSON_AddItemToObject(root, "high", cJSON_CreateNumber(166.9)); //在对象中插入浮点数值 cJSON_AddItemToObject(root, "married", cJSON_CreateFalse()); //在对象中插入bool量 /* 在root节点下添加relation子对象 */ cJSON_AddItemToObject(root, "relation", relation); /* 在relation节点下添加love子对象 */ cJSON_AddItemToObject(relation, "love", love); cJSON_AddItemToObject(love, "name", cJSON_CreateString("noName")); cJSON_AddItemToObject(love, "loveTime", cJSON_CreateNumber(6)); cJSON_AddItemToObject(love, "age", cJSON_CreateNumber(19)); cJSON_AddItemToObject(friend, "name", cJSON_CreateString("noName")); cJSON_AddItemToObject(friend, "loveTime", cJSON_CreateNumber(6)); cJSON_AddItemToObject(friend, "age", cJSON_CreateNumber(19)); /* 在relation节点下添加interest子对象 */ cJSON_AddItemToObject(relation, "interest", interest); cJSON_AddItemToArray(interest,cJSON_CreateString("篮球")); //在数组中插入字符串 cJSON_AddItemToArray(interest,cJSON_CreateNumber(66.666)); //在数组中插入数值 cJSON_AddItemToArray(interest,cJSON_CreateNumber(19)); cJSON_AddItemToArray(interest,cJSON_CreateTrue()); //在数组中插入bool cJSON_AddItemToArray(interest,friend); //在数组中插入对象 cjson_str = cJSON_Print(root); //将json转化为字符串, /* 将json写入文件 */ FILE *pf = fopen("test.json","w"); fwrite(cjson_str,strlen(cjson_str),1,pf); fclose(pf); free(cjson_str); //释放cJSON_Print()函数申请的内存 cJSON_Delete(root); //删除一个cJSON实体和所有子实体 return 0; } |
下面是生成json文件过程中常用到的cJSON库接口:
- 这些调用创建适当类型的cJSON项:
cJSON_CreateNull(void) :创建NULL类型cJSON_CreateTrue(void) :创建bool->truecJSON_CreateFalse(void) :创建bool->falsecJSON_CreateBool(cJSON_bool boolean) 创建bool(cJSON_True,cJSON_False)cJSON_CreateNumber(double num) :创建整型或浮点型值。cJSON_CreateString(const char *string) :创建字符串
- 创建对象/数组接口
cJSON_CreateArray(void) :创建数组cJSON_CreateObject(void) :创建对象
- 向数组或对象中添加元素
cJSON_AddItemToArray(cJSON *array, cJSON *item) - array:一般是cJSON_CreateArray()函数创建的指针。
- item:要添加的元素。
可以是cJSON_CreateNumber()等创建cJSON项的函数的返回值。也可以是cJSON_CreateObject()等创建的对象。
cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
- 数组或者对象的插入/代替相关操作
- cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem);
- array:要操作的数组。
- which:要插入的位置Index.
- newitem:要插入的值
- cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
- cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
- string:要代替的属性名称。
- cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem);
- 从数组/对象中隔离/删除指定元素。
cJSON_DetachItemFromArray(cJSON *array, int which) cJSON_DeleteItemFromArray(cJSON *array, int which) cJSON_DetachItemFromObject(cJSON *object, const char *string) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
- 批量创建相关接口。
cJSON_CreateIntArray(const int *numbers, int count) - 批量创建int型数组。
- numbers:int型的值数组指针
- count:numbers数组中的成员数量。
cJSON_CreateFloatArray(const float *numbers, int count) cJSON_CreateDoubleArray(const double *numbers, int count) cJSON_CreateStringArray(const char **strings, int count)
- 复制一个cjson item.
cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) - item:指定要复制的item.
- recurse:是否递归。
使用cJSON库解析json文件
要解析的json文件为上面的json文件,可以对照学习。
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 | #include <stdio.h> #include <stdlib.h> #include "cJSON.h" #include <sys/stat.h> void main(void) { /* 获取文件大小 */ struct stat fileBuff; stat("test.json",&fileBuff); printf("file size:%ld\n",fileBuff.st_size); /* 为解析json文件分配缓存 */ char *pBuff = (char *)malloc(fileBuff.st_size); FILE *pf = fopen("test.json","r"); fread(pBuff,fileBuff.st_size,1,pf);//将文件读入缓存 fclose(pf); printf("file content:\n"); //printf("%s\n",pBuff); /* 解析json文件 */ cJSON *root = NULL; root = cJSON_Parse(pBuff); if(root == NULL){ printf("parse error:%s\n",cJSON_GetErrorPtr()); return; } /* 方式1. 通过属性名查找 */ cJSON *pName = cJSON_GetObjectItem(root, "name"); if(pName == NULL){ printf("error\n"); } else if(pName->type == cJSON_String){ printf("%s\n",pName->valuestring); } /* 方式2. 按照链表的格式,遍历查找 */ for(cJSON *pCur = root->child;pCur != NULL; pCur = pCur->next){ switch(pCur->type){ case cJSON_Invalid:break; case cJSON_False :printf("%s = false\n",pCur->string);break; case cJSON_True :printf("%s = true\n", pCur->string);break; case cJSON_NULL :printf("%s = null\n", pCur->string);break; case cJSON_Number :printf("%s = %d\n",pCur->string,pCur->valueint);break; case cJSON_String :printf("%s = %s\n",pCur->string,pCur->valuestring);break; case cJSON_Array :printf("%s = array\n",pCur->string);break; case cJSON_Object :printf("%s = object\n",pCur->string);break; default:printf("type:%d\n",pCur->type);break; } } /* 获取数组大小和元素 */ cJSON *pTemp = cJSON_GetObjectItem(root, "relation"); cJSON *pInterest = cJSON_GetObjectItem(pTemp, "interest"); int ItemsNum = cJSON_GetArraySize(pInterest); //获取数组大小 printf("%s items is %d\n",pInterest->string,ItemsNum); for(int i = 0; i < ItemsNum; i++){ cJSON *pCur = cJSON_GetArrayItem(pInterest,i); switch(pCur->type){ case cJSON_Invalid:break; case cJSON_False :printf("[%d] = false\n",i);break; case cJSON_True :printf("[%d] = true\n",i);break; case cJSON_NULL :printf("[%d] = null\n",i);break; case cJSON_Number :printf("[%d] = %f\n",i,pCur->valuedouble);break; case cJSON_String :printf("[%d] = %s\n",i,pCur->valuestring);break; case cJSON_Array :printf("[%d] = array\n",i);break; case cJSON_Object :printf("[%d] = object\n",i);break; default:printf("type[%d]:%d\n",i,pCur->type);break; } } /* 获取数组中对象的元素 */ pTemp = cJSON_GetArrayItem(pInterest,4); cJSON *pt = cJSON_GetObjectItem(pTemp, "name"); printf("%s:%s\n",pt->string,pt->valuestring); cJSON_Delete(root); } |
下面是解析json文件过程中常用到的cJSON库接口:
- 将json文件解析为链表的函数
cJSON_Parse(const char *value) - value:要解析的json文件字符串。
- return:返回解析后的链表头。
- 如果出现解析错误,可以调用cJSON_GetErrorPtr()找到解析错误位置。
cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) - 是cJSON_Parse()的增强版。
- return_parse_end:可以获取解析失败的位置.和cJSON_GetErrorPtr()的功能类似。
- require_null_terminated:检查剩余未解析字符串是否是空字符串.若不为空字符串,则会释放内存,返回空。
- 查找解析出错的地方
char *cJSON_GetErrorPtr(void) :此函数会返回解析出错地方的指针。
- 操作数组相关的函数。
cJSON_GetArraySize(const cJSON *array) :获取数组的大小。cJSON_GetArrayItem(const cJSON *array, int index) :获取数组[index] 的对象指针。
- 操作对象相关的函数。
cJSON_GetObjectItem(const cJSON * const object, const char * const string) - 通过string查找对应的object对象的元素指针。
- json链表和json字符串之间的转化函数
char *cJSON_Print(const cJSON *item) - 他会将传入的json对象转化为字符串。一般用于输出到文件。在转换过程中函数会自动分配内存来存放转换后的字符串。所以使用完毕后需要用户自己释放内存。
char *cJSON_PrintUnformatted(const cJSON *item) - 相对于cJSON_Print(),它在转换过程中没有添加换行等格式化字符。打印出的json字符串是紧凑的不用换行,适合传输json字符串时使用。
cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) - prebuffer:事先指定分配一个缓冲区,如果足够大,则可以节省不断重新分配空间的时间。
- fmt:是否格式化。相当于cJSON_Print()和cJSON_PrintUnformatted()函数的区别。
- 其他类似于cJSON_Print()函数。
cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) - 类似于cJSON_Print()函数。只不过将json对象转化后的字符串存放在buffer缓存区中。
cJSON_Delete(cJSON *c) :释放一个cJSON实体和所有子实体分配的内存。const char*cJSON_Version(void) :获取cjson库的版本号字符串。
关于技术交流
此处后的文字已经和题目内容无关,可以不看。
qq群:825695030
微信公众号:嵌入式的日常
如果上面的文章对你有用,欢迎打赏、点赞、评论。