文章目录

前言一、JSON介绍使用json的优点JSON 的不足JSON 存储使用JSON的时机

二、JSON的语言介绍数据类型

三、c/c++解析JSON数据cJSON介绍cJSON存储数据cJSON的api函数的使用

解析JSON

前言

因项目中是选用json,传输网络数据。因此要解析json数据。所以前来学习

一、JSON介绍

JSON是一种轻量级的、基于文本的、开放的数据交换格式。它本身不提供任何方法(函数),非常适合在网络中进行传输。 其中,在 JSON 中,使用以下两种方式来表示数据: (1)Object(对象):键/值对(名称/值)的集合,使用花括号{ }定义。在每个键/值对中,以键开头,后跟一个冒号:,最后是值。多个键/值对之间使用逗号,分隔。 (2)Array(数组):值的有序集合,使用方括号[ ]定义,数组中每个值之间使用逗号,进行分隔。 如下所示:

{

"Name":"C语言中文网",

"Url":"http://c.biancheng.net/",

"Tutorial":"JSON",

"Article":[

"JSON 是什么?",

"JSONP 是什么?",

"JSON 语法规则"

]

}

使用json的优点

JSON 并不是唯一能够实现在互联网中传输数据的方式,除此之外还有一种 XML 格式。但是JSON 比 XML 的可读性更高,而且 JSON 更加简洁,更容易理解。 与 XML 相比,JSON 具有以下优点: (1)结构简单、紧凑:与 XML 相比,JSON 遵循简单、紧凑的风格,有利于程序员编辑和阅读,而 XML 相对比较复杂; (2)更快:JSON 的解析速度比 XML 更快(因为 XML 与 HTML 很像,在解析大型 XML 文件时需要消耗额外的内存),存储同样的数据,JSON 格式所占的存储空间更小; (3)可读性高:JSON 的结构有利于程序员阅读。

JSON 的不足

(1)只有一种数字类型:JSON 中只支持 IEEE-754 双精度浮点格式,因此无法使用 JSON 来存储许多编程语言中多样化的数字类型; (2)没有日期类型:在 JSON 中只能通过日期的字符串(例如:1970-01-01)或者时间戳(例如:1632366361)来表示日期; (3)没有注释:在 JSON 中无法添加注释; (4)冗长:虽然 JSON 比 XML 更加简洁,但它并不是最简洁的数据交换格式,对于数据量庞大或用途特殊的服务,您需要使用更加高效的数据格式。

JSON 存储

JSON 数据可以存储在 .json 格式的文件中(与 .txt 格式类似,都属于纯文本文件),也可以将 JSON 数据以字符串的形式存储在数据库、Cookie、Session 中。

使用JSON的时机

(1)定义接口 前后端分离,后端返回的数据; 开发 API,例如百度、高德的一些开放接口。 RPC 远程调用;

(2)序列化 序列化是将程序中的对象直接转换为可保存或者可传输的数据,但这样会保存对象的类型信息,无法做到跨语言使用,例如我们使用 Python 将数据序列化到硬盘,然后使用 Java 来读取这份数据,这时由于不同编程语言的数据类型不同,就会造成读取失败。如果在序列化之前,先将对象信息转换为 JSON 格式,则不会出现此类问题。

二、JSON的语言介绍

数据类型

1.字符串 JSON 中的字符串需要使用双引号定义(注意:不能使用单引号),字符串中可以包含零个或多个 Unicode 字符。另外,JSON 的字符串中也可以包含一些转义字符。代码实例如下:

{

"name":"C语言中文网",

"url":"http://c.biancheng.net/",

"title":"JSON 数据类型"

}

2.数字 JSON 中不区分整型和浮点型,只支持使用 IEEE-754 双精度浮点格式来定义数字。此外,JSON 中不能使用八进制和十六进制表示数字,但可以使用 e 或 E 来表示 10 的指数。代码实例如下:

{

"number_1" : 210,

"number_2" : -210,

"number_3" : 21.05,

"number_4" : 1.0E+2

}

3.布尔值 JSON 中的布尔值与编程语言中相似,有两个值,分别为 true(真)和 false(假)。代码实例如下:

{

"message" : true,

"pay_succeed" : false

}

4.空 null(空)是 JSON 中的一个特殊值,表示没有任何值,当 JSON 中的某些键没有具体值时,就可以将其设置为 null。代码实例如下:

{

"id" : 1,

"visibility" : true,

"popularity" : null

}

5.对象 在 JSON 中,对象是一个无序的 、键/值对的集合,一个对象以左花括号{开始,以右花括号}结束,左右花括号之间为对象中的若干键/值对。键/值对中,键必须是字符串类型(即使用双引号将键包裹起来),而值可以是 JSON 中的任意类型,键和值之间需要使用冒号:分隔开,不同的键/值对之间需要使用逗号,分隔开。代码实例如下:

{

"author": {

"name": "C语言中文网",

"url": "http://c.biancheng.net/"

}

}

6.数组 数组是值的有序集合,JSON 中的数组需要使用方括号[ ]定义,方括号中为数组中的若干值,值可以是 JSON 中支持的任意类型(例如字符串、数字、布尔值、对象、数组等),每个值之间使用逗号,分隔开。代码实例如下:

{

"array":[

{

"name":"C语言中文网",

"url":"http://c.biancheng.net/",

"course":"JSON教程"

},

[

"JSON是什么?",

"JSON语法规则",

"JSON数据类型"

],

"JSON",

18,

true

]

}

三、c/c++解析JSON数据

通过操作cJSON开源库(小巧玲珑,且是纯C的)来解析JSON字符串。去官网下载一下,把那个库的cJSON.c和cJSON.h文件拷贝到自己的项目中即可。接下来是对这个库的学习,并解析JSON数据

cJSON介绍

对于了解cJSON,其实主要了解下cJSON数据存储,以及API即可。毕竟,我们学到还是为了用。

cJSON存储数据

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;

其中,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 // 对象

cJSON的api函数的使用

1.cJSON对象的创建,元素的插入

// 定义对象 { }

cJSON *interest = cJSON_CreateObject();

// 插入元素,对应 键值对

cJSON_AddItemToObject(interest, "basketball", cJSON_CreateString("篮球"));// 当值是字符串时,需要使用函数cJSON_CreateString()创建

cJSON_AddItemToObject(interest, "badminton", cJSON_CreateString("羽毛球"));

// 或者使用宏进行添加

//cJSON_AddStringToObject(interest, "badminton", "羽毛球"); // 或者这样写

实现效果如下:

"interest": {

"basketball": "篮球",

"badminton": "羽毛球"

}

// 定义 [ ] 数组

cJSON *color = cJSON_CreateArray();

// 往数组中添加元素

cJSON_AddItemToArray(color, cJSON_CreateString("black"));

cJSON_AddItemToArray(color, cJSON_CreateString("white"));

实现效果如下:

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

// 定义 { } 对象

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);

实现效果如下:

"like": [

{ "game": "马里奥", "price": 66.6 },

{ "game": "魂斗罗", "price": 77.7 }

]

// 定义 [ ] 数组

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);

实现效果如下:

"education": [

[ "小学", "初中" ],

[ "高中", "大学" ]

]

2.字符串生成cjson指针的函数,使用后需要调用cJSON_Delete进行释放

extern cJSON *cJSON_Parse(const char *value);

// 释放cJSON_Parse返回的指针

extern void cJSON_Delete(cJSON *c);

3.cjson指针指针生成字符串的函数

// 这个生成的字符串有做格式调整

extern char *cJSON_Print(cJSON *item);

// 这个没有作格式调整,就是一行字符串显示

extern char *cJSON_PrintUnformatted(cJSON *item);

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

// 打印控制台查看

char *cPrint = cJSON_Print(root);

char *cPrintUnformatted = cJSON_PrintUnformatted(root);

printf("cJSON_Print:\n%s\n", cPrint); // cJSON_Print:有做格式调整

printf("cJSON_PrintUnformatted:\n%s\n", cPrintUnformatted); // cJSON_PrintUnformatted:没有做格式调整

// 返回的字符串指针需要自己释放

free(cPrint);

free(cPrintUnformatted);

解析JSON

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

1.打开文件读取josn数据

// 打开文件

FILE *file = NULL;

file = fopen(FILE_NAME, "r");

if (file == NULL) {

printf("Open file fail!\n");

return;

}

// 获得文件大小

struct stat statbuf;

stat(FILE_NAME, &statbuf);

int fileSize = statbuf.st_size;

printf("文件大小:%d\n", 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("读取文件失败!\n");

fclose(file);

return;

}

printf("%s\n", jsonStr);

fclose(file);

2.使用读取到的json数据初始化cJSON指针

// 将读取到的json字符串转换成json变量指针

cJSON *root = cJSON_Parse(jsonStr);

if (!root) {

printf("Error before: [%s]\n", cJSON_GetErrorPtr());

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.直接通过键进行解析的 解析时需要使用结构体中的type类型进行判断,这是为了安全性考虑! 解析时也可以使用cJSON_Print函数去获取字符串或者使用结构体中的valuestring进行获取,但是要注意的是,使用cJSON_Print函数去获取字符串需要free掉获取到的指针,否则会造成内存泄漏!

// 解析:"name": "小明",

item = cJSON_GetObjectItem(root, "name");

if (item != NULL) {

/* 写法一:*/

// 判断是不是字符串类型

//if (item->type == cJSON_String) {

// v_str = cJSON_Print(item); // 通过函数获取值

// printf("name = %s\n", v_str);

// free(v_str); // 通过函数返回的指针需要自行free,否则会导致内存泄漏

// v_str = NULL;

//}

/* 写法二: */

// 判断是不是字符串类型

if (item->type == cJSON_String) {

v_str = item->valuestring; // 此赋值是浅拷贝,不需要现在释放内存

printf("name = %s\n", v_str);

}

}

// 解析:"age": "23",

item = cJSON_GetObjectItem(root, "age");

if (item != NULL) { // 合法性检查

if (item->type == cJSON_Number) { // 判断是不是数字

v_int = item->valueint; // 获取值

printf("age = %d\n", 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\n", 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\n", v_str);

free(v_str);

v_str = NULL;

}

本项目中,主要是使用直接通过键进行解析的,学到这已经能够完成项目的设计了。 对于其他的,比如解析数组啊,解析对象啊,之类的操作,等有时间用到了再来补充。毕竟还要按照计划时间来完成项目的学习。

参考文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: