C语言解析 json文件

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库中的内容,并不深入,如果需要深入的了解可以查看文首的大佬链接,这是本人的第一篇文章,如果有什么错误希望大家能及时回复,希望对大家有帮助

  • 13
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值