c json解析/创建详解及代码示例

本文详细介绍了cJSON库如何解析和创建JSON格式的数据,包括JSON的基本语法、cJSON的核心结构体以及代码示例,展示了如何解析JSON文件并创建自定义JSON对象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. JSON 定义

JSON (JavaScript Object Notation) is a lightweight data-interchange format.
It is easy for humans to read and write. It is easy for machines to parse and generate.

2. json 介绍及语法

2.1 json 介绍

JSON: JavaScript Object Notation(JavaScript 对象表示法)
JSON 是轻量级的文本数据交换格式

2.2 json 语法

数据在名称/值对中,key : value
数据由逗号分隔
大括号 {} 保存对象
中括号 [] 保存数组,数组可以包含多个对象

2.2.1 JSON key 键

JSON key 必须是字符串

2.2.2 JSON value 值

JSON 值可以是:字符串, 数字, 对象, 数组, 布尔值或 null

  1. 数字(整数或浮点数)
    JSON 数字可以是整型或者浮点型:

    { “age”:30 }

  2. 字符串(在双引号中)

    { “name”:“hani”}

  3. 逻辑值(true 或 false)
    JSON 布尔值可以是 true 或者 false:

    { “flag”:true }

  4. 数组(在中括号[]中)
    数组值必须是合法的 JSON 数据类型(字符串, 数字, 对象, 数组, 布尔值或 null)。
    如:

    {
    “name”:“hani”,
    “age”:18,
    “sites”:[ “Google”, “baidu”, “google” ]
    }

数组可包含多个对象:

{
	"sites": [
		{ "name":"hani" , "url":"www.hani.com" }, 
		{ "name":"google" , "url":"www.google.com" }, 
		{ "name":"baidu" , "url":"www.baidu.com" }
	]
}
  1. 对象(在大括号{}中)
    JSON 对象使用在大括号({})中书写。
    对象可以包含多个 key/value(键/值)对。
    key 必须是字符串,value 可以是合法的 JSON 数据类型(字符串, 数字, 对象, 数组, 布尔值或 null)。
    key 和 value 中使用冒号(:)分割。
    每个 key/value 对使用逗号(,)分割。

JSON 对象在大括号 {} 中书写:

{key1 : value1, key2 : value2, ... keyN : valueN }

对象可以包含多个名称/值对:

{ "name":"hani" , "url":"www.hani.com" }
  1. null
    JSON 可以设置 null 值:

    { “runoob”:null }

3. cJSON 的核心结构体 cJSON

typedef struct cJSON {
	struct cJSON*next,*prev;	/* 遍历数组或对象链的前向或后向链表指针*/
	struct cJSON *child;    	/*数组或对象的孩子节点*/
	int type;               	/* key的类型*/
	char *valuestring;      	/*字符串值*/
	int valueint;           	/* 整数值*/
	double valuedouble;     	/* 浮点数值*/
	char *string;           	/* key的名字*/
} cJSON;

3.1 cJSON 说明:

1、cJSON是使用链表来存储数据的,其访问方式很像一颗树。每一个节点可以有兄弟节点,通过next/prev指针来查找,它类似双向链表;每个节点也可以有孩子节点,通过child指针来访问,进入下一层。只有节点是对象或数组时才可以有孩子节点。

3.2 cjson 源码 github

https://github.com/DaveGamble/cJSON
只需要 cJSON.c cJSON.h 两个文件即可

4. 代码示例-解析json

4.1. json 示例文件: test.txt

{
	"filename":   "test.tar",
	"fileid":     "888",
	"port":       1024,
	"subfile":      [{
					"subfileName":  "aaa.txt",
					"size": 102.00,
					"author":   [{
										"name": "hani"
								}, {
										"name": "lufei"
								}]
										}, {
					"subfileName":  "bbb.docx",
					"size": 560.00,
					"author":   [{
										"name": "suolong"
								}, {
										"name": "namei"
								}]
			}]
}

4.2 解析json 主函数: jsonTest.c

说明: 解析json中的数组有两种方法:
方法一: cJSON_GetArraySize + for
方法二: cJSON_ArrayForEach

#include <stdio.h> 
#include <string.h> 
#include <sys/types.h> 
#include <stdlib.h> 
#include <unistd.h> 

#include "cJSON.h" 


/* parseJson : parse a key-value pair */
int parseJson(char *pcJsonStr)  
{  
	cJSON *pstJRoot 	= NULL;
	cJSON *pstJFileID 	= NULL;
	cJSON *pstFileName  = NULL;
	cJSON *pstJPort   	= NULL;
	cJSON *pstSubFile   = NULL;
	cJSON *pstSize    	= NULL;
	cJSON *pstAuthor    = NULL;
	cJSON *pstSubFileArray  = NULL;
	cJSON *pstAuthorArray   = NULL;
	cJSON *pstAuthorRoot	= NULL;
	cJSON *pstAuthorName    = NULL;
	cJSON *pstSubFileRoot	= NULL;
	cJSON *pstSubFileName	= NULL;
	
	int iSubFileSize = 0;
	int iSubFileIndex = 0;
	int iAuthorSize = 0;
	int iAuthorIndex = 0;
	
	pstJRoot = cJSON_Parse(pcJsonStr);  
	if (!pstJRoot)  
	{  
		printf("Error before: [%s]\n",cJSON_GetErrorPtr());  
		return -1;  
	}  
	
	printf("---- Start parse ----\n"); 
	
	/* fileName */
	pstFileName=cJSON_GetObjectItem(pstJRoot,"fileName"); 
	if (cJSON_IsString(pstFileName) && (pstFileName->valuestring != NULL))
	{
		printf("%s=%s\n", pstFileName->string,pstFileName->valuestring);  
	}
	
	/* fileid */
	pstJFileID=cJSON_GetObjectItem(pstJRoot,"fileid"); 
	if (cJSON_IsString(pstJFileID) && (pstJFileID->valuestring != NULL))
	{
		printf("%s=%s\n", pstJFileID->string,pstJFileID->valuestring);  
	}
	
	/* port */
	pstJPort=cJSON_GetObjectItem(pstJRoot,"port"); 
	if (cJSON_IsNumber(pstJPort))
	{
		printf("%s=%d\n", pstJPort->string,pstJPort->valueint);  
	}
	
	/* 方法一: cJSON_GetArraySize for */
	///* subfile array */
	//pstSubFileArray = cJSON_GetObjectItem(pstJRoot, "subfile");
	//iSubFileSize = cJSON_GetArraySize(pstSubFileArray);
	//
	//for(iSubFileIndex = 0; iSubFileIndex < iSubFileSize; iSubFileIndex++)
	//{
	//    pstSubFileRoot = cJSON_GetArrayItem(pstSubFileArray, iSubFileIndex);
	//	if(NULL == pstSubFileRoot)
	//    {
	//		break;
	//	}
	//	
	//	/* subfileName */
	//    pstSubFileName = cJSON_GetObjectItemCaseSensitive(pstSubFileRoot, "subfileName");
	//	if (cJSON_IsString(pstSubFileName) && (pstSubFileName->valuestring != NULL))
	//	{
	//		printf(" %s=%s\n", pstSubFileName->string,pstSubFileName->valuestring);  
	//	}
	//
	//	/* size */
	//    pstSize = cJSON_GetObjectItemCaseSensitive(pstSubFileRoot, "size");
	//    if (cJSON_IsNumber(pstSize))
	//    {
	//        printf(" %s=%f\n", pstSize->string,pstSize->valuedouble);
	//    }
	//	
	//	/* author array */
	//	pstAuthorArray = cJSON_GetObjectItem(pstSubFileRoot, "author");
	//	iAuthorSize = cJSON_GetArraySize(pstAuthorArray);
	//
	//	for(iAuthorIndex = 0; iAuthorIndex < iAuthorSize; iAuthorIndex++)
	//	{
	//		pstAuthorRoot = cJSON_GetArrayItem(pstAuthorArray, iAuthorIndex);
	//		if(NULL == pstAuthorRoot)
	//		{
	//			break;
	//		}
	//		
	//		/* author name */
	//		pstAuthorName = cJSON_GetObjectItemCaseSensitive(pstAuthorRoot, "name");
	//		if (cJSON_IsString(pstAuthorName) && (pstAuthorName->valuestring != NULL))
	//		{
	//			printf("   %s=%s\n", pstAuthorName->string,pstAuthorName->valuestring);  
	//		}
	//	}
	//	
	//}
	
	/* 方法二: cJSON_ArrayForEach */
	/* subfile object */
	pstSubFile = cJSON_GetObjectItem(pstJRoot, "subfile");
	cJSON_ArrayForEach(pstSubFileRoot, pstSubFile)
	{
		/* subfileName */
		pstSubFileName = cJSON_GetObjectItemCaseSensitive(pstSubFileRoot, "subfileName");
		if (cJSON_IsString(pstSubFileName) && (pstSubFileName->valuestring != NULL))
		{
			printf(" %s=%s\n", pstSubFileName->string,pstSubFileName->valuestring);  
		}
	
		/* size */
		pstSize = cJSON_GetObjectItemCaseSensitive(pstSubFileRoot, "size");
		if (cJSON_IsNumber(pstSize))
		{
			printf(" %s=%f\n", pstSize->string,pstSize->valuedouble);
		}
		
		/* author object */
		pstAuthor = cJSON_GetObjectItem(pstSubFileRoot, "author");
		cJSON_ArrayForEach(pstAuthorRoot, pstAuthor)
		{
			/* author name */
			pstAuthorName = cJSON_GetObjectItemCaseSensitive(pstAuthorRoot, "name");
			if (cJSON_IsString(pstAuthorName) && (pstAuthorName->valuestring != NULL))
			{
				printf("  %s=%s\n", pstAuthorName->string,pstAuthorName->valuestring);  
			}
		}
	}
	
	cJSON_Delete(pstJRoot);  

	return 0;  
}  


/* read file */
void readFile(char *pcFileName)  
{  
	FILE *pFile;  
	int iFileLen;  
	char *pcData;  
	
	pFile=fopen(pcFileName,"rb");  
	fseek(pFile,0,SEEK_END);  
	iFileLen=ftell(pFile);  
	fseek(pFile,0,SEEK_SET);  
	pcData=(char*)malloc(iFileLen+1);  
	fread(pcData,1,iFileLen,pFile);  
	fclose(pFile);  
	
	printf("read file %s complete, iFileLen=%d.\n",pcFileName,iFileLen);  
	
	int ret = parseJson(pcData); 
	if(-1 == ret)
	{
		printf("parseJson failed.\n");
	}
	free(pcData);  
}  

int main(int argc, char **argv)  
{  
	readFile("test.txt");  
	return 0;  
}

4.3 编译及测试结果

4.3.1 文件目录

-rw-r--r-- 1 root root 77833 Nov 16  2020 cJSON.c
-rw-r--r-- 1 root root 15828 Nov 16  2020 cJSON.h
-rw-r--r-- 1 root root  3007 Jan  1 11:21 jsonTest.c
-rw-r--r-- 1 root root   734 Jan  1 11:06 test.txt

4.3.2 编译命令

编译命令,编译json 静态库

gcc -c cJSON.c
ar -cr libjson.a cJSON.o
gcc -o res jsonTest.c -L. -ljson

编译后:

-rw-r--r-- 1 root root 77833 Nov 16  2020 cJSON.c
-rw-r--r-- 1 root root 15828 Nov 16  2020 cJSON.h
-rw-r--r-- 1 root root 43616 Jan  2 00:36 cJSON.o
-rw-r--r-- 1 root root  3007 Jan  1 11:21 jsonTest.c
-rw-r--r-- 1 root root 45706 Jan  2 00:38 libjson.a
-rwxr-xr-x 1 root root 43392 Jan  2 00:39 res
-rw-r--r-- 1 root root   734 Jan  1 11:06 test.txt

4.3.3 结果

[root@glusterfs json]# ./res 
read file test.txt complete, iFileLen=734.
---- Start parse ----
filename=test.tar
fileid=888
port=1024
subfileName=aaa.txt
size=102.000000
name=hani
name=lufei
subfileName=bbb.docx
size=560.000000
name=suolong
name=namei

5. 代码示例-封装json

5.1 代码示例 createJson.c

#include <stdio.h> 
#include <string.h> 
#include <sys/types.h> 
#include <stdlib.h> 
#include <unistd.h> 

#include "cJSON.h" 


/* createJson : create json */
int createJson()  
{  
	cJSON *pstJRoot 	= NULL;
	cJSON *pstSubFile1   = NULL;
	cJSON *pstSubFile2   = NULL;
	cJSON *pstAuthor1_name1    = NULL;
	cJSON *pstAuthor1_name2    = NULL;
	cJSON *pstAuthor2_name1    = NULL;
	cJSON *pstAuthor2_name2    = NULL;
	
	cJSON *pstSubFileArray1  = NULL;
	cJSON *pstSubFileArray2  = NULL;
	cJSON *pstAuthorArray1	 = NULL;
	cJSON *pstAuthorArray2	 = NULL;
	
	char *pcRes = NULL;
	
	printf("---- Start create json ----\n"); 
	
	pstJRoot = cJSON_CreateObject();
	if(pstJRoot == NULL)    
	{
		printf("[error]: create pstJRoot failed. \n");
		return -1;
	}
	
	cJSON_AddStringToObject(pstJRoot, "filename", "test.tar");
	cJSON_AddStringToObject(pstJRoot, "fileid", "888");
	cJSON_AddNumberToObject(pstJRoot, "port", 1024);
	
	/* create pstSubFileArray1 */
	pstSubFileArray1 = cJSON_AddArrayToObject(pstJRoot, "subfile");
	pstSubFile1 = cJSON_CreateObject();
	if(pstSubFile1 == NULL)    
	{
		printf("[error]: create pstSubFile1 failed. \n");
		return -1;
	}
	
	cJSON_AddItemToArray(pstSubFileArray1, pstSubFile1);
	cJSON_AddStringToObject(pstSubFile1, "subfileName", "aaa.txt");
	cJSON_AddNumberToObject(pstSubFile1, "size", 102);
	
	/* create pstAuthorArray1 */
	pstAuthorArray1 = cJSON_AddArrayToObject(pstSubFile1, "author");
	pstAuthor1_name1 = cJSON_CreateObject();
	if(pstAuthor1_name1 == NULL)    
	{
		printf("[error]: create pstAuthor1_name1 failed. \n");
		return -1;
	}
	cJSON_AddItemToArray(pstAuthorArray1, pstAuthor1_name1);
	cJSON_AddStringToObject(pstAuthor1_name1, "name", "hani");
	
	
	pstAuthor1_name2 = cJSON_CreateObject();
	if(pstAuthor1_name2 == NULL)    
	{
		printf("[error]: create pstAuthor1_name2 failed. \n");
		return -1;
	}
	cJSON_AddItemToArray(pstAuthorArray1, pstAuthor1_name2);
	cJSON_AddStringToObject(pstAuthor1_name2, "name", "lufei");
	
	
	
	/* create pstSubFileArray2 */
	pstSubFileArray2 = cJSON_AddArrayToObject(pstJRoot, "subfile");
	pstSubFile2 = cJSON_CreateObject();
	if(pstSubFile2 == NULL)    
	{
		printf("[error]: create pstSubFile2 failed. \n");
		return -1;
	}
	
	cJSON_AddItemToArray(pstSubFileArray2, pstSubFile2);
	cJSON_AddStringToObject(pstSubFile2, "subfileName", "bbb.docx");
	cJSON_AddNumberToObject(pstSubFile2, "size", 102);
	
	/* create pstAuthorArray2 */
	pstAuthorArray2 = cJSON_AddArrayToObject(pstSubFile2, "author");
	pstAuthor2_name1 = cJSON_CreateObject();
	if(pstAuthor2_name1 == NULL)    
	{
		printf("[error]: create pstAuthor2_name1 failed. \n");
		return -1;
	}
	cJSON_AddItemToArray(pstAuthorArray2, pstAuthor2_name1);
	cJSON_AddStringToObject(pstAuthor2_name1, "name", "suolong");
	
	pstAuthor2_name2 = cJSON_CreateObject();
	if(pstAuthor2_name2 == NULL)    
	{
		printf("[error]: create pstAuthor2_name2 failed. \n");
		return -1;
	}
	cJSON_AddItemToArray(pstAuthorArray2, pstAuthor2_name2);
	cJSON_AddStringToObject(pstAuthor2_name2, "name", "namei");
	
	pcRes = cJSON_Print(pstJRoot);
	if (pcRes == NULL)
	{
		printf("[error]: cJSON_Print failed. \n");
	}
	printf("result:\n%s\n",pcRes);
	
	
	cJSON_Delete(pstJRoot);  
	free(pcRes);
	return 0;  
}  

int main(int argc, char **argv)  
{  
	int res = createJson();
	if(-1 == res)
	{
		printf("createJson failed \n");
	}
	return 0;  
}

5.2 结果

[root@glusterfs json]# gcc -o res createJson.c -L. -ljson
[root@glusterfs json]# ./res 
---- Start create json ----
result:
{
		"filename":     "test.tar",
		"fileid":       "888",
		"port": 1024,
		"subfile":      [{
						"subfileName":  "aaa.txt",
						"size": 102,
						"author":       [{
										"name": "hani"
								}, {
										"name": "lufei"
								}]
				}],
		"subfile":      [{
						"subfileName":  "bbb.docx",
						"size": 102,
						"author":       [{
										"name": "suolong"
								}, {
										"name": "namei"
								}]
				}]
}

6. 重点!!!pcJsonStr (pcRes)需要释放

上面的 createJson.c 中: free(pcRes);

 	pcRes = cJSON_Print(pstJRoot);
	if (pcRes == NULL)
	{
		printf("[error]: cJSON_Print failed. \n");
	}
	printf("result:\n%s\n",pcRes);
	
	
	cJSON_Delete(pstJRoot);  
	free(pcRes);.

因为: cJSON_Print 内调用了 cJSON_malloc

参考:

https://cloud.tencent.com/developer/article/1055318
https://github.com/DaveGamble/cJSON
https://www.json.org/json-en.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值