C语言解析 json文件
使用C语言解析json文件,使用过几次每次都要查资料,所以写个帖子以后再碰到就不用花太多时间了,有兴趣的同学可以简单借鉴
下载cJSON库
可以访问这位大佬的这篇文章
https://blog.csdn.net/nanfeibuyi/article/details/86605234
直面大佬
我用大佬的方法编译链接库的时候出现过一点问题,这里也记录一下
https://blog.csdn.net/yjk13703623757/article/details/53217377
直面大佬
我用的是文章中的第二个方法将解压文件夹中的文件放到
/usr/loca/lib
后面的步骤按链接文章中的操作就行了
不使用.so文件,直接使用.c .h文件
如果不想要链接库的话可以下载这个文件
cJSON库https://sourceforge.net/projects/cjson/
里面有.c和.h文件编译的时候放到一起就行了
里面的函数和cJSON库中的函数是一样的,只是使用起来不需要配置和链接库
这里在贴个大佬的连接,讲的十分详细
https://blog.csdn.net/Mculover666/article/details/103796256
直面大佬
Linux下的一个json工具
这个也是参考大佬的, 可装也可以不用装,效果如下:
这是大佬的链接:https://linux.cn/article-12915-1.html
添加链接描述
cJson源码中一些需要了解的内容
1. 将json文件解析成cJSON对象后,cJSON内部使用链表的方式存储键值对,所以使用后需要及时释放内存
2. typedef struct cJSON {
struct cJSON *next,*prev; // 用于链表的构建
struct cJSON *child;
int type; // 记录当前cJSON结构体存放的类型(cJSON_Object、cJSON_Array、cJSON_String、cJSON_Number、cJSON_NULL、cJSON_True、cJSON_False)
char *valuestring; // 存放字符串值
int valueint; // 存放整型值
double valuedouble; // 存放浮点型值
char *string; // 存放键名
} cJSON;
Linux 和 win都通用的一个代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "cJSON.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <unistd.h>
// #define WRITE_
// #define READ_
// #define CHANG_
int main(void)
{
//编辑json文件内容
#ifdef WRITE_
//打开json文件并创建数据
//创建一个空的文档对象
cJSON* json = cJSON_CreateObject();
//向文档中增加一个键值对{"name":"zww"}
cJSON_AddItemToObject(json, "name", cJSON_CreateString("calmReed"));
cJSON_AddItemToObject(json, "age", cJSON_CreateNumber(20));
//宏的使用 效果和上面的一样,只是看起来更简短
cJSON_AddNumberToObject(json, "score", 12);
cJSON_AddStringToObject(json, "address", "jiangxi");
cJSON* array = NULL; //数组
cJSON_AddItemToObject(json, "love", array = cJSON_CreateArray()); //创建一个数组到json这个类中
//创建一个对象
cJSON *myjson = cJSON_CreateObject();
//创建键值对到对象中
cJSON_AddItemToObject(myjson, "who", cJSON_CreateString("me"));
//在数组中添加一个对象
cJSON_AddItemToArray(array, myjson);
//向数组中添加一个数字
cJSON_AddItemToArray(array, cJSON_CreateNumber(20));
//将json结构体格式化到缓冲区
char *buf = cJSON_Print(json);
//打开文件用以写入json数据
FILE *fp = fopen("test2.json", "w");
fwrite(buf, 1, strlen(buf), fp);
// 使用之后注意释放字符串内存
free(buf);
fclose(fp);
//释放json结构体所占的内存
cJSON_Delete(json);
#endif
//读取json文件内容
#ifdef READ_
//打开文件并读取数据
//打开保存JSON数据的文件
int fd = open("test2.json",O_RDWR);
if(fd < 0)
{
perror("open fail\n");
return -1;
}
//读取文件中的数据
char buf[2048]={0};
int ret = read(fd, buf, sizeof(buf));
if(ret == -1)
{
perror("read error");
return -1;
}
close(fd);
//把该字符串数据转换成JSON数据(对象) 开始的对象为最外层的对象
cJSON *root=cJSON_Parse(buf);
if(root == NULL)
{
printf("parse error\n");
return -1;
}
/*
* 取对象中的value值
* */
cJSON *_name = cJSON_GetObjectItem(root,"name");//获取键"name"对应的JSON值
if(_name == NULL)
{
printf("GetObjec error\n");
return -1;
}
// 如果单纯只是为了打印,直接使用_name->valuestring就行
char *_name_c = (char *)malloc(strlen(_name->valuestring)+1);
strcpy(_name_c, _name->valuestring);
printf("name = [%s]\n", _name_c);
free(_name_c);
/*
* 获取数组中的内容
*
* */
//当前的value1 是一个数组对象
cJSON * _love = cJSON_GetObjectItem(root,"love");
if(_love == NULL)
{
printf("GetObjectItem error\n");
return -1;
}
//获取该数组对象的大小
int _len = cJSON_GetArraySize(_love);
printf("love arry len = %d\n",_len);
//根据下标获取对象
int i = 0;
cJSON * type_value = NULL;
for(i=0;i<_len;i++)
{
//获取数组中的每个内容, 如果对象则进一步解析
type_value = cJSON_GetArrayItem(_love,i);
if(type_value == NULL)
{
printf("GetObjectItem error\n");
return -1;
}
if(type_value->type == cJSON_Object)
{
cJSON *_who = cJSON_GetObjectItem(type_value, "who");
printf("love[%d]=%s\n",i, _who->valuestring);
}
if(type_value->type == cJSON_Number)
{
printf("love[%d]=%d\n",i, type_value->valueint);
}
}
cJSON_Delete(root);
#endif
#ifdef CHANG_
/*
extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem);
extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
*/
//修改数据并保存
int fd = open("test2.json",O_RDWR);
if(fd < 0)
{
perror("open fail\n");
return -1;
}
//读取文件中的数据
char buf[2048]={0};
int ret = read(fd, buf, sizeof(buf));
if(ret == -1)
{
perror("read error");
return -1;
}
lseek(fd, 0, SEEK_SET);//注意将fd放到开头
//把该字符串数据转换成JSON数据(对象) 开始的对象为最外层的对象
cJSON *root=cJSON_Parse(buf);
if(root == NULL)
{
printf("parse error\n");
return -1;
}
//修改值
cJSON_ReplaceItemInObject(root, "name",cJSON_CreateString("calm_reed"));
cJSON_ReplaceItemInObject(root, "age",cJSON_CreateNumber(11));
//修改数组中的对象的值
cJSON *arry_love = cJSON_GetObjectItem(root,"love");
cJSON *type_who = cJSON_GetArrayItem(arry_love, 0);
cJSON_ReplaceItemInObject(type_who, "who",cJSON_CreateString("you"));
// 直接修改cJSON中的值也是可以的, 需要注意的是如果是整型,需要用valuedouble才能修改成功
// cJSON *value_num = cJSON_GetArrayItem(arry_love, 1);
// value_num->valuedouble = 111;
//将json结构体格式化到缓冲区
char *_out = cJSON_Print(root);
strcpy(buf, _out);
//将修改后的数据写入到文件中
write(fd, buf, strlen(buf));
free(_out);
close(fd);
//释放json结构体所占的内存
cJSON_Delete(root);
#endif
return 0;
}
代码分为三个模块,可以使用define进行切换
//#define WRITE_ //写
//#define READ_ //读
//#define CHANG_ //改
1. 写json文件
流程:
1.创建cJSON *对象 ->
2.使用json库中的函数创建信息 ->
3.将对象转换为字符串格式 ->
4.将字符串写入到文件中
上面的代码已经将大部分的种类创建列举出来了,其他的创建也是大同小异
需要注意的是 :
1.数组中似乎只能创建key没有value, 如果要键值对的话,需要在数组中创建对象
2.需要及时释放内存cJSON_Delete
2. 读json文件内容
流程:
1.打开文件 ->
2.将文件内容放到字符串中 ->
3.将字符串转换为cJSON *对象 ->
4.使用json库中的函数获取需要的信息
运行结果
name = [calmReed]
love arry len = 2
love[0]=me
love[1]=20
读取和添加也差不多只不过是函数从Add变成了Get
如果有多层嵌套的解析也是如此,一层一层的获取
3. 修改json文件
流程:
1.打开文件 ->
2.将文件内容放到字符串中 ->
3.将字符串转换为cJSON *对象 ->
4.使用json库中的函数修改信息
运行结果
原来的内容
```php
{
"name": "calmReed",
"age": 20,
"score": 12,
"address": "jiangxi",
"love": [{
"who": "me"
}, 20]
}
修改后的内容
{
"name": "calm_reed",
"age": 11,
"score": 12,
"address": "jiangxi",
"love": [{
"who": "you"
}, 20]
}
总结几个需要注意的点:
1.修改json文件内容简单来说就是覆盖原有文件中的内容,但我们已经将所有文件内容复制到了字符串中,需要将文件描述符放到文件的开头,否则就不是修改而是追加了
2.cJSON_Print()所返回的指针源码中是使用malloc申请过内存的,所以使用之后需要free()释放
3.关于修改的函数问题:
https://blog.csdn.net/Mculover666/article/details/103796256
这篇文章中的第二点
/*
* String:用于表示该键值对的名称;
type:用于表示该键值对中值的类型;
valuestring:如果键值类型(type)是字符串,则将该指针指向键值;
valueint:如果键值类型(type)是整数,则将该指针指向键值;
valuedouble:如果键值类型(type)是浮点数,则将该指针指向键值;
* */
可以通过修改结构体中的内容来修改键值,使用源码提供的函数其内部是将原来链表中的节点(需要修改的节点)进行了删除,然后重新创建了一个节点替换上去
本文章主要面向于如何使用 cJSON库中的内容,并不深入,如果需要深入的了解可以查看文首的大佬链接,这是本人的第一篇文章,如果有什么错误希望大家能及时回复,希望对大家有帮助