本文主要介绍了C++使用cjson操作Json格式文件(创建、插入、解析、修改、删除),文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
为什么要学习解析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");
return;
}
printf("%s\n", jsonStr);
fclose(file);
使用读取到的json数据初始化cJSON指针
// 将读取到的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;
/