CC++ 使用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介绍

  1. 首先介绍一下json数据:
    在这里插入图片描述
    上图的json数据就是这篇博客将要操作的,将会对其进行创建、解析、修改、删除操作。
    其中这里包含项目中常用的封装和解析。

  2. 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;
    
  3. 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		// 对象
    
  4. 字符串生成cjson指针的函数,使用后需要调用cJSON_Delete进行释放

    extern cJSON *cJSON_Parse(const char *value);
    
    // 释放cJSON_Parse返回的指针
    extern void   cJSON_Delete(cJSON *c);
    
  5. cjson指针指针生成字符串的函数

    // 这个生成的字符串有做格式调整
    extern char  *cJSON_Print(cJSON *item);
    // 这个没有作格式调整,就是一行字符串显示
    extern char  *cJSON_PrintUnformatted(cJSON *item);
    

    使用这个两个函数一定一定一定要释放它们返回的指针内存,否则会造成内存泄漏。

其他的就不介绍了,都会在下面中使用到!


三、封装Json

  1. { }

    "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", "羽毛球");	// 或者这样写
    
  2. [ ]

    "color": [ "black", "white"]
    

    代码实现上述效果:

    // 定义 [ ] 数组
    cJSON *color = cJSON_CreateArray();
    // 往数组中添加元素
    cJSON_AddItemToArray(color, cJSON_CreateString("black"));
    cJSON_AddItemToArray(color, cJSON_CreateString("white"));
    
  3. [ { }, { } ]

    "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);
    
  4. [ [ ], [ ] ]

    "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);
    
  5. { { }, { } }

    "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);
    
  6. 定义根节点 也即是最外层 { }

    // 创建跟对象
    cJSON *root = cJSON_CreateObject();
    
  7. 将上面定义的{ } 与 [ ] 都插入到跟节点{ }中

    // 将子项插入根项中
    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");	// 或者这样写也是可以的
    
  8. 打印控制台查看

    // 打印控制台查看
    char *cPrint = cJSON_Print(root);
    char *cPrintUnformatted = cJSON_PrintUnformatted(root);
    printf("cJSON_Print:
    %s
    ", cPrint);		// cJSON_Print:有做格式调整
    printf("cJSON_PrintUnformatted:
    %s
    ", cPrintUnformatted);	// cJSON_PrintUnformatted:没有做格式调整
    // 返回的字符串指针需要自己释放
    free(cPrint);
    free(cPrintUnformatted);
    

    记得使用cJSON_Print 和 cJSON_PrintUnformatted返回来的字符指针需要free掉内存!
    在这里插入图片描述

  9. 写入文件中

    // 打开文件
    FILE *file = NULL;
    file = fopen(FILE_NAME, "w");	// FILE_NAME ==> "jss.json"
    if (file == NULL) {
    	printf("Open file fail!
    ");
    
    	// 释放指针内存
    	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("写入文件失败!
    ");
    }
    
    fclose(file);
    free(cjValue);
    
  10. 释放掉cJSON指针

    // 释放指针内存
    cJSON_Delete(root);

  11. 把代码写好后,编译运行,会在自己的项目路径中创建一个JSON文件,并写入内容,文件内容如下:
    在这里插入图片描述


四、解析Json

解析时需要使用结构体中的type类型进行判断,这是为了安全性考虑!

解析时也可以使用cJSON_Print函数去获取字符串或者使用结构体中的valuestring进行获取,但是要注意的是,使用cJSON_Print函数去获取字符串需要free掉获取到的指针,否则会造成内存泄漏!

下面解析会提供两种方式进行解析,第一种是固定的,写死的方式;第二种是灵活的的方式解析!

  1. 打开文件读取josn数据

    // 打开文件
    FILE *file = NULL;
    file = fopen(FILE_NAME, "r");
    if (file == NULL) {
    	printf("Open file fail!
    ");
    	return;
    }
    
    
    // 获得文件大小
    struct stat statbuf;
    stat(FILE_NAME, &statbuf);
    int fileSize = statbuf.st_size;
    printf("文件大小:%d
    ", 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("读取文件失败!
    ");
    	return;
    }
    printf("%s
    ", jsonStr);
    fclose(file);
    
  2. 使用读取到的json数据初始化cJSON指针

    // 将读取到的json字符串转换成json变量指针
    cJSON *root = cJSON_Parse(jsonStr);
    if (!root) {
    	const char *err = cJSON_GetErrorPtr();
    	printf("Error before: [%s]
    ", err);
    	free((void *)err);
    	free(jsonStr);
    	return;
    }
    free(jsonStr);
    
  3. 定义一些下面需要使用到的变量

    cJSON *item = NULL;
    char *v_str = NULL;
    double v_double = 0.0;
    int v_int = 0;
    bool v_bool = false;
    
  4. 直接通过键进行解析的

    // 解析:"name":	"小明",
    item = cJSON_GetObjectItem(root, "name");	
    if (item != NULL) {
    	/* 写法一:*/
    	// 判断是不是字符串类型
    	//if (item->type == cJSON_String) {
    	//	v_str = cJSON_Print(item);		// 通过函数获取值
    	//	printf("name = %s
    ", v_str);
    	//	free(v_str);					// 通过函数返回的指针需要自行free,否则会导致内存泄漏
    	//	v_str = NULL;
    	//}
    	
    
    	/* 写法二: */
    	// 判断是不是字符串类型
    	if (item->type == cJSON_String) {	
    		v_str = item->valuestring;		// 此赋值是浅拷贝,不需要现在释放内存
    		printf("name = %s
    ", v_str);
    	}
    	
    }
    
    
    
    // 解析:"age":	"23",
    item = cJSON_GetObjectItem(root, "age");
    if (item != NULL) {	// 合法性检查
    	if (item->type == cJSON_Number) {		// 判断是不是数字
    		v_int = item->valueint;			// 获取值
    		printf("age = %d
    ", 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
    ", 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
    ", v_str);
    	free(v_str);
    	v_str = NULL;
    }
    
  5. 解析对象 { }
    也就是解析下图内容:

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用cjson解析一个json文件可以分为以下几步: 1. 引入cjson的头文件,如:`#include "cJSON.h"` 2. 读取json文件内容到一个字符串变量中,如: ``` char* json_content = NULL; FILE* fp = fopen("example.json", "rb"); fseek(fp, 0, SEEK_END); long file_size = ftell(fp); rewind(fp); json_content = (char*)malloc(file_size + 1); fread(json_content, file_size, 1, fp); fclose(fp); json_content[file_size] = '\0'; ``` 3. 使用cJSON的`cJSON_Parse()`函数解析json字符串,如: ``` cJSON* root = cJSON_Parse(json_content); if (root == NULL) { printf("Error before: [%s]\n", cJSON_GetErrorPtr()); } ``` 4. 通过`cJSON_GetObjectItem()`函数获取json对象的成员变量,如: ``` cJSON* name = cJSON_GetObjectItem(root, "name"); const char* name_value = name->valuestring; ``` 5. 释放cJSON对象的内存,如: ``` cJSON_Delete(root); ``` 完整的代码示例可以参考以下代码: ``` #include "cJSON.h" #include <stdio.h> #include <stdlib.h> int main() { char* json_content = NULL; FILE* fp = fopen("example.json", "rb"); fseek(fp, 0, SEEK_END); long file_size = ftell(fp); rewind(fp); json_content = (char*)malloc(file_size + 1); fread(json_content, file_size, 1, fp); fclose(fp); json_content[file_size] = '\0'; cJSON* root = cJSON_Parse(json_content); if (root == NULL) { printf("Error before: [%s]\n", cJSON_GetErrorPtr()); return 1; } cJSON* name = cJSON_GetObjectItem(root, "name"); const char* name_value = name->valuestring; printf("name: %s\n", name_value); cJSON_Delete(root); free(json_content); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值