前言
在工作中遇到用cJSON用来配置文件或者数据存储。今天写一篇博客来记录一下cJSON基础使用。
cJSON简介
JSON(JavaScriptObject Notation)是一种轻量级的数据交换格式。它基于JavaScript的一个子集。JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯。这些特性使JSON成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和生成。
为何选择cJSON
cJSON是一个超轻巧,携带方便,单文件,简单的可以作为ANSI-C标准的JSON解析器。
github 地址:
https://github.com/DaveGamble/cJSON
下载完后,解压从里面找到两个文件(cJSON.c、cJSON.h),复制到工程里面。只需在函数中包含头文件(#include “cJSON.h”),然后和cJSON.c一起编译即可使用。
Linux 下编译方式:
gcc cJSON.c test.c -o jsontest -lm
cJSON的核心结构体
cJSON的核心结构体就是一个cJSON,其结构如下:
typedef struct cJSON {
struct cJSON*next,*prev; /* 遍历数组或对象链的前向或后向链表指针*/
struct cJSON *child; /*数组或对象的孩子节点*/
int type; /* 键的类型*/
char *valuestring; /*字符串值*/
int valueint; /* 整数值*/
double valuedouble; /* 浮点数值*/
char *string; /* 键的名字*/
} cJSON;
cJSON是用双链表写的,通过next / prev指针来查找。每个节点也可以有孩子节点,通过child指针来访问。
常用接口函数
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
用于将字符串解析成json对象,若失败则返回NULL。
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
释放cJSON_Parse()分配出来的内存空间。
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
返回数组中的项数
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
调用cJSON_GetObjectItem()函数,可从cJSON结构体中查找某个子节点名称(键名称),如果查找成功可把该子节点序列化到cJSON结构体中。
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
将cJSON实体呈现为用于传输/存储的文本。
解析JSON格式
要想解析JSON格式,首先需要实现读文件的功能,然后开始JSON字符串的解析。解析文件可以大致分为以下几步骤:
1、在Linux上想要获取文件大小,可以选用stat函数获取文件大小信息
2、申请一段内存,将文件中的文本读取到buffer中
3、通过cJSON_Parse接口解析buffer中的字符串
4、用cJSON_GetObjectItem 接口解析获取指定字段
json是一种组织良好的数据格式,因而JSON中的内容解析后,都可以通过以上数据结构进行处理。
例如,对于下面的json内容:
test.json
{
"people":[
{"firstName":"minger","lastName":"minger","email":"[email protected]","age":23,"height":1.67},
{"firstName":"jinmeng","lastName":"meng","email":"[email protected]","age":18,"height":1.177},
{"email":"[email protected]","firstName":"chen","lastName":"jun","age":26,"height":1.75}
]
}
test_cJSON.c 实现了结构体数组的解析
#include
#include
#include
#include
#include
#include //stat
#include "cJSON.h"
#define FILENAME "./test.json"
typedef struct
{
int id;
char firstName[32];
char lastName[32];
char email[64];
int age;
float height;
}people;
//解析一个结构数组
int cJSON_to_struct_array(char *text, people worker[])
{
cJSON *json,*arrayItem,*item,*object;
int i = 0;
json=cJSON_Parse(text);
if (!json)
{
printf("Error before: [%s]\n",cJSON_GetErrorPtr());
}
else
{
arrayItem=cJSON_GetObjectItem(json,"people"); // 获取json对象中的people节点
if(arrayItem!=NULL)
{
int size=cJSON_GetArraySize(arrayItem); //获取数组大小
printf("cJSON_GetArraySize: size=%d\n",size);
for(i=0;i<size;i++)
{
printf("i=%d\n",i);
object=cJSON_GetArrayItem(arrayItem,i);
item=cJSON_GetObjectItem(object,"firstName"); // 获取json对象中的firstName节点
if(item!=NULL)
{
printf("cJSON_GetObjectItem: type=%d, string is %s\n",item->type,item->string);
memcpy(worker[i].firstName,item->valuestring,strlen(item->valuestring));
}
item=cJSON_GetObjectItem(object,"lastName");
if(item!=NULL)
{
printf("cJSON_GetObjectItem: type=%d, string is %s, valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(worker[i].lastName,item->valuestring,strlen(item->valuestring));
}
item=cJSON_GetObjectItem(object,"email");
if(item!=NULL)
{
printf("cJSON_GetObjectItem: type=%d, string is %s, valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(worker[i].email,item->valuestring,strlen(item->valuestring));
}
item=cJSON_GetObjectItem(object,"age");
if(item!=NULL)
{
printf("cJSON_GetObjectItem: type=%d, string is %s, valueint=%d\n",item->type,item->string,item->valueint);
worker[i].age=item->valueint;
}
else
{
printf("cJSON_GetObjectItem: get age failed\n");
}
item=cJSON_GetObjectItem(object,"height");
if(item!=NULL)
{
printf("cJSON_GetObjectItem: type=%d, string is %s, value=%f\n",item->type,item->string,item->valuedouble);
worker[i].height=item->valuedouble;
}
}
}
printf("\n\n");
for(i=0;i<3;i++)
{
printf("i=%d, firstName=%s,lastName=%s,email=%s,age=%d,height=%f\n",
i,
worker[i].firstName,
worker[i].lastName,
worker[i].email,
worker[i].age,
worker[i].height);
}
cJSON_Delete(json);
}
return 0;
}
size_t get_file_size(const char *filepath)
{
if(NULL == filepath)
return 0;
struct stat filestat;
memset(&filestat,0,sizeof(struct stat));
/*获取文件信息*/
if(0 == stat(filepath,&filestat))
return filestat.st_size;
else
return 0;
}
void read_file(char *filename)
{
FILE *fp;
people worker[3]={{0}};
/*get file size*/
size_t size = get_file_size(filename);
if(0 == size)
{
printf("get_file_size failed!!!\n");
}
/*malloc memory*/
char *buf = malloc(size+1);
if(NULL == buf)
{
printf("malloc failed!!!\n");
}
memset(buf,0,size+1);
fp=fopen(filename,"rb");
fread(buf,1,size,fp);
fclose(fp);
printf("read file %s complete, size=%d.\n",filename,size);
cJSON_to_struct_array(buf, worker);
free(buf);
}
int main(int argc, char **argv)
{
read_file(FILENAME);
return 0;
}
编译:
gcc cJSON.c test_cJSON.c -o test_cJSON -lm
输出结果:
{
"person":
{
"firstName":"minger",
"lastName":"ming",
"email":"[email protected]",
"age":18,
"height":1.77
}
}
需要用到接口函数
cJSON*cJSON_Parse(const char *value);
cJSON*cJSON_GetObjectItem(cJSON *object,const char *string);
voidcJSON_Delete(cJSON *c);
解析一个结构体
int cJSON_to_struct(char *json_string, people *person)
{
cJSON *item;
cJSON *root=cJSON_Parse(json_string);
if (!root)
{
printf("Error before: [%s]\n",cJSON_GetErrorPtr());
return -1;
}
else
{
cJSON *object=cJSON_GetObjectItem(root,"person");
if(object==NULL)
{
printf("Error before: [%s]\n",cJSON_GetErrorPtr());
cJSON_Delete(root);
return -1;
}
printf("cJSON_GetObjectItem: type=%d, key is %s, value is %s\n",object->type,object->string,object->valuestring);
if(object!=NULL)
{
item=cJSON_GetObjectItem(object,"firstName");
if(item!=NULL)
{
printf("cJSON_GetObjectItem: type=%d, string is %s, valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(person->firstName,item->valuestring,strlen(item->valuestring));
}
item=cJSON_GetObjectItem(object,"lastName");
if(item!=NULL)
{
printf("cJSON_GetObjectItem: type=%d, string is %s, valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(person->lastName,item->valuestring,strlen(item->valuestring));
}
item=cJSON_GetObjectItem(object,"email");
if(item!=NULL)
{
printf("cJSON_GetObjectItem: type=%d, string is %s, valuestring=%s\n",item->type,item->string,item->valuestring);
memcpy(person->email,item->valuestring,strlen(item->valuestring));
}
item=cJSON_GetObjectItem(object,"age");
if(item!=NULL)
{
printf("cJSON_GetObjectItem: type=%d, string is %s, valueint=%d\n",item->type,item->string,item->valueint);
person->age=item->valueint;
}
else
{
printf("cJSON_GetObjectItem: get age failed\n");
}
item=cJSON_GetObjectItem(object,"height");
if(item!=NULL)
{
printf("cJSON_GetObjectItem: type=%d, string is %s, valuedouble=%f\n",item->type,item->string,item->valuedouble);
person->height=item->valuedouble;
}
}
cJSON_Delete(root);
}
return 0;
}
总结
相比于python一条搞定解析来说,C语言中解析JSON似乎显得有些麻烦,但cJSON无疑是一个超轻量级的JSON器。cJSON只需一个C文件,一个头文件,包含到项目源码中即可解析。
扫二维码关注微信公众号,获取技术干货