JSON是什么

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。JSON 使用 Javascript语法来描述数据对象,但是 JSON 仍然独立于语言和平台。

JSON 基本语法

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

例如:

1
{ name : C Primer pluse, pages : 626 }

JSON值(value)的类型

1
2
3
4
5
6
7
8
/* cJSON Types: */
#define cJSON_False 0
#define cJSON_True 1
#define cJSON_NULL 2
#define cJSON_Number 3
#define cJSON_String 4
#define cJSON_Array 5
#define cJSON_Object 6
  • 逻辑值(true 或 false)

    1
    {"flag":true}
  • null

    1
    {"name":null}
  • NUMBER 数字(整数或浮点数)

    1
    {"pages":200, "price":35.00}
  • STRING 字符串(在双引号""中)

    1
    {"book":"C Primer pluse"}
  • ARRAY 数组(在中括号[]中)

    1
    2
    3
    4
    5
    [
    {"name":"C Primer pluse", "author":"Stephen Prata"},
    {"name":"C程序设计", "author":"谭浩强"},
    {"name":"C陷阱与缺陷", "author":"Andrew Koenig"}
    ]
  • OBJECT 对象(在大括号{}中)

    1
    {"name":"C Primer pluse", "author":"Stephen Prata"}

    当然对象内部也可以是数组,如:

    1
    2
    3
    4
    5
    6
    7
    {
    "books":[
    {"name":"C Primer pluse", "author":"Stephen Prata"},
    {"name":"C程序设计", "author":"谭浩强"},
    {"name":"C陷阱与缺陷", "author":"Andrew Koenig"}
    ]
    }

    对象 books 内部是一个数组,该数组又包含了三个对象

cJSON又是个啥

cJSON是一个基于C的JSON解析库,这个库非常简短,源码内容只包含一个cJSON.h头文件和一个cJSON.c源文件,支持JSON的解析和封装,需要调用时,只需要#include "cJSON.h"就可以使用了。

cJSON源文件开源项目地址:https://sourceforge.net/projects/cjson/

cJSON编程实例

例子1

先演示一个最简单的JSON数据,如何使用cJSON库来解析。

用于测试JSON数据,我们先用一个char型的字符串了保存,注意,由于JSON对象的key和value都需要使用引号(数值或逻辑型value除外),所以,使用C语言的字符串来保存JSON数据,在遇到引号时,要加反斜杠来转义

解析JSON数据时,首先要调用 cJSON_Parse() 这个函数,将JSON数据解析为 cJSON 型的对象:

1
cJSON *srcJsonData = cJSON_Parse(jsonData);

然后就可以使用cJSON库中提供的各种函数来操作这个对象。比如 :

1
value = cJSON_GetObjectItem(srcJsonData,"name");

就是通过 cJSON_GetObjectItem() 来获取JSON数据中的一项数据,并通过指定key的方式来获取对应的value。

整个测试程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"

void main(void)
{
char jsonData[] = "{\"name\":\"C Primer pluse\",\"pages\":626}";

cJSON *srcJsonData = cJSON_Parse(jsonData);
if(!srcJsonData)
{
printf("Error:%s\r\n",cJSON_GetErrorPtr());
}
else
{
/*获取Json数据的内容*/
cJSON *value;
value = cJSON_GetObjectItem(srcJsonData,"name");/*通过key来获取value*/
if(value->type == cJSON_String)/*字符串型的value*/
{
printf("书名:%s\r\n",value->valuestring);
}

value = cJSON_GetObjectItem(srcJsonData,"pages");/*通过key来获取value*/
if(value->type == cJSON_Number)/*数值型的value*/
{
printf("页数:%d\r\n",value->valueint);
}

cJSON_Delete(srcJsonData);
}
}

运行结果:

1
2
3
4
5
6
书名:C Primer pluse
页数:626

--------------------------------
Process exited after 0.01452 seconds with return value 0
请按任意键继续. . .

例子2

上面是一个最基本的测试程序,JSON数据也是直接通过C语言的字符串保存的。

实际的使用中,JSON数据的内容较为庞大,再使用C语言的字符串来保存,则会及其麻烦(想想那一堆反斜杠)。

所以,一般都是使用文件的形式来保存JSON数据

准备一个原始数据用于测试,如下面的data.txt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"class":"C语言书籍",
"books":[{
"name":"C Primer pluse",
"author":"Stephen Prata",
"publishing":"人民邮电出版社"
},

{
"name":"C程序设计",
"author":"谭浩强",
"publishing":"清华大学出版社"
},

{
"name":"C陷阱与缺陷",
"author":"Andrew Koenig",
"publishing":"人民邮电出版社"
}]
}

先来分析下这个JSON数据的结构:

  • 最外面的大括号,表示这个一个JSON对象
  • 对象里面有2个数据,key1是class,key2是books
  • books的value又是一个中括号表示的数组
  • 数组内又包含了3个对象,每个对象有3个数据,key1是name,key2是author,key3是publishing

解析这种JSON文件,使用要使用 fopen() 来打开这个文件:

1
FILE *fp = fopen("data.txt", "r");

这里还要使用fseek()ftell()来计算文件的大小,目的是用于后面的分配内存时指定大小。

然后使用fread()将文件内存读入内存中分配的buf中:

1
fread(buf, fileSize, sizeof(char), fp);

接着,还是使用cJSON_Parse() 将JSON数据解析为 cJSON 型的对象

1
cJSON *srcJsonData = cJSON_Parse(buf);

然后就可以使用cJSON库中提供的各种函数来操作这个对象了。

这次会用到cJSON_GetObjectItem()cJSON_GetArrayItem()cJSON_GetArraySize()cJSON_Print()等函数。

注意是使用完cJSON_Print()后,要使用free()来释放。

具体的测试程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "cJSON.h"

void main(void)
{
/*打开JSON文件*/
FILE *fp = fopen("data.txt", "r");
if(fp == NULL)
{
return;
}

/*计算文件大小*/
int fileSize;
fseek(fp, 0, SEEK_END);/*先移到文件末尾*/
fileSize = ftell(fp);/*计算文件的大小*/
printf("fileSize: %d\r\n", fileSize);
fseek(fp, 0, SEEK_SET);/*再移到文件开头*/

/*根据文件大小分配内存,并读取文件到内存*/
char *buf = (char *)malloc(fileSize * sizeof(char));
memset(buf, 0, fileSize);
int ret = fread(buf, fileSize, sizeof(char), fp);
if(ret == -1)
{
fclose(fp);
return;
}
printf("%s\r\n",buf);
fclose(fp);

/*把该字符串数据转成JSON数据*/
cJSON *srcJsonData = cJSON_Parse(buf);
free(buf);
if(srcJsonData == NULL)
{
printf("err\r\n");
return;
}

cJSON *value;
/*根据key值(class)获取对应的value*/
value = cJSON_GetObjectItem(srcJsonData, "class");
if(value == NULL)
{
printf("GetObjectItem err\r\n");
cJSON_Delete(srcJsonData);
return;
}

/*把value转成字符串输出*/
char *data = cJSON_Print(value);
printf("class = %s\r\n",data);
free(data);


/*根据key值(books)获取对应的value*/
value = cJSON_GetObjectItem(srcJsonData, "books");
if(value == NULL)
{
printf("GetObjectItem err\r\n");
cJSON_Delete(srcJsonData);
return;
}

/*获取该数组对象的大小*/
int len = cJSON_GetArraySize(value);
printf("books data: len=%d\r\n",len);

/*访问books中的每一项*/
int i = 0;
for(i=0; i<len; i++)
{
/*先获取每一条信息*/
cJSON *tmpValue = cJSON_GetArrayItem(value,i);

/*再获取每条信息中的具体内容*/
cJSON *nameValue = cJSON_GetObjectItem(tmpValue,"name");
cJSON *authorValue = cJSON_GetObjectItem(tmpValue,"author");
cJSON *publishValue = cJSON_GetObjectItem(tmpValue,"publishing");

if(nameValue == NULL || authorValue == NULL || publishValue == NULL)
{
printf("GetObjectItem err\r\n");
cJSON_Delete(srcJsonData);
return;
}

/*打印出来*/
char *print1 = cJSON_Print(nameValue);
char *print2 = cJSON_Print(authorValue);
char *print3 = cJSON_Print(publishValue);
printf("[%d] %s \t %s \t %s\r\n",i+1,print1,print2,print3);
free(print1);
free(print2);
free(print3);
}
cJSON_Delete(srcJsonData);
}

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
fileSize: 433
{
"class":"C语言书籍",
"books":[{
"name":"C Primer pluse",
"author":"Stephen Prata",
"publishing":"人民邮电出版社"
},

{
"name":"C程序设计",
"author":"谭浩强",
"publishing":"清华大学出版社"
},

{
"name":"C陷阱与缺陷",
"author":"Andrew Koenig",
"publishing":"人民邮电出版社"
}]
}
class = "C语言书籍"
books data: len=3
[1] "C Primer pluse" "Stephen Prata" "人民邮电出版社"
[2] "C程序设计" "谭浩强" "清华大学出版社"
[3] "C陷阱与缺陷" "Andrew Koenig" "人民邮电出版社"

--------------------------------
Process exited after 0.01578 seconds with return value 0
请按任意键继续. . .