目录
1,测试读写的 test.json 文件内容(文件路径 E:\test.json)
前言
cJSON 是用C语言编写的一个超轻量,可移植,单文件的 JSON 解析器,它是个开源的项目,它只有 cJSON.h 和 cJSON.c 两个文件,使用时只需要在对应的 include 和 src 目录添加进去就可以使用了,cJSON 下载地址
一,cJSON 数据类型
- << 是左移运算符,左移运算符介绍
- 这是 cJSON 用于类型判断的自定义宏,只需要了解是啥类型就行
二,cJSON 结构体
- 整个 JSON 文档里的数据其实就是一个树形结构,每个节点是一个双向链表,child 指向子 JSON 项
- string 表示的是 键值对中 key 的名称
三,创建 Json 项
- 常用的七个创建指定 数据类型 JSON 项
- 创建 数组 的同时进行初始化
- 以下不常用
四,往 JSON 项中添加数据
- 针对 数组 通过 item 传入 JSON 项(数组或对象)
- 针对 对象 通过 键(string)值(item)对 传入 JSON 项(数组或对象)
- 往已有的 JSON 对象中添加指定 键(name)值(第三个参数)对 类型数据
- 以下不常用
五,从 JSON 父项中删除 JSON 子项
- 通过 指针,下标 或 键值 从父 JSON 项中删除指定项
- sensitive 表示对传入的 键值 大小写敏感
六,更新 JSON 项的指定位置数据
- 针对 数组 传入的 下标(which) 不能超过数组长度
- 针对 对象 传入的 子对象(item)或 键值(string) 要存在
- sensitive 表示对传入的 键值(string) 大小写敏感
七,拷贝 JSON 项
- 返回值为传入的 JSON项(item)的拷贝值
- recurse 表示是否递归拷贝,也就是是否拷贝 item 的 子JSON 项(数组或对象)
八,比较两个 JSON 项是否相等
- case_sensitive 表示比对的 JSON项(数组或对象) 的 键值 是否区分大小写
九,判断当前 JSON 项的类型
十,获取当前 JSON 项的 value 值
- 传入 item(数组或对象)会先判断其是否为接口名称类型,不是返回 NULL 是返回其 value 值
- 可以用来检查 JSON 文档是否格式写错
- 传入键值(string)返回其值(子JSON项),sensitive表示区分大小写
- 判断是否存在指定 键值(string)的 子JSON项
- 以下接口有对应注释进行解释
十一,删除 JSON 项(重点)
- 一定要记得调用这接口,它会将当前节点及其子节点都会进行删除(内存释放)
十二,解析 JSON 项
- 第一个经常用来解析 JSON 格式的字符串
- 以下两个不常用
十三,获取 JSON 项的序列化值
- 返回一个带格式化(有换行)的字符串(和JSON文档中的格式一样)
- 返回一个未格式化(没有换行)的字符串(所有数据都在一行上)
- prebuffer是指定缓冲区的大小
- 没用过
十四,获取当前 cJSON 版本
十五,JSON 钩子模块(了解就行)
十六,案例答疑解惑
1,测试读写的 test.json 文件内容(文件路径 E:\test.json)
{
"FirstName": "Fu",
"LastName": "Cong",
"Age": 24,
"Address": {
"Street": "首创悦榕汇",
"City": "BeiJing",
"Country": "BeiJing"
},
"Phone numbers": [
"+44 12345",
678910
]
}
2,所需要的头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cJSON.h"
3,写 Json 文件接口实现
void writeJson()
{
cJSON *obj_root;
obj_root = cJSON_CreateObject(); //创建根数据对象
cJSON_AddStringToObject(obj_root,"FirstName","Fu");
cJSON_AddStringToObject(obj_root,"LastName","Cong");
cJSON_AddNumberToObject(obj_root, "Age",24);
cJSON *subObj_addr;
subObj_addr = cJSON_CreateObject();
cJSON_AddItemToObject(subObj_addr,"Street",cJSON_CreateString("首创悦榕汇"));
cJSON_AddItemToObject(subObj_addr,"City",cJSON_CreateString("BeiJing"));
cJSON_AddItemToObject(subObj_addr,"Country",cJSON_CreateString("BeiJing"));
cJSON *subObj_arr;
subObj_arr = cJSON_CreateArray(); //创建数组对象
cJSON_AddItemToArray(subObj_arr,cJSON_CreateString("+44 12345"));
cJSON_AddItemToArray(subObj_arr,cJSON_CreateNumber(678910));
cJSON_AddItemToObject(obj_root,"Address",subObj_addr);
cJSON_AddItemToObject(obj_root,"Phone numbers",subObj_arr);
char *out = cJSON_Print(obj_root);
FILE *file = fopen("E:\\test.json","w");
if(file != NULL){
fputs(out,file); //写入文件流
fclose(file); //关闭文件流
//一定要记得释放内存
cJSON_Delete(obj_root);
free(out);
}
}
效果图如下
4,读 Json 文件接口实现
//返回指定文件的所有内容
char *readFile(char *path)
{
FILE *file = fopen(path,"r");;
char *data = NULL;
long length; //文件大小
if(file != NULL){
//文件打开成功
fseek(file,0,SEEK_END); //将文件流光标移动到文件末尾
length = ftell(file); //获取文件内容的大小(相对于文件开头的位移量来表示)
data = (char*)malloc((length +1)*sizeof(char));
rewind(file); //将文件光标重置到文件开头位置
length = fread(data,1,length,file); //一次性读取所有字符串
data[length] = 0;
fclose(file); //关闭文件流
return data;
}
return NULL;
}
//解析从 JSON 文件中读取的数据
void readJson()
{
char *jsonData = readFile("E:\\test.json");
if(jsonData == NULL){
printf("%s","File is empty");
}
cJSON *json_root = cJSON_Parse(jsonData);
if(cJSON_IsObject(json_root)){
//JSON根数据是对象
cJSON *subobj_one = cJSON_GetObjectItem(json_root,"FirstName");
if(cJSON_IsString(subobj_one)){
printf("%s:%s\n","FirstName",cJSON_GetStringValue(subobj_one));
}
cJSON *subobj_two = cJSON_GetObjectItem(json_root,"LastName");
if(cJSON_IsString(subobj_two)){
printf("%s:%s\n","LastName",cJSON_GetStringValue(subobj_two));
}
cJSON *subobj_three = cJSON_GetObjectItem(json_root,"Age");
if(cJSON_IsNumber(subobj_three)){
printf("%s:%2.0f\n","Age",cJSON_GetNumberValue(subobj_three));
}
cJSON *subObj_four = cJSON_GetObjectItem(json_root,"Address");
if(cJSON_IsObject(subObj_four)){
//子 JSON 项是对象
cJSON *subSubobj_one = cJSON_GetObjectItem(subObj_four,"Street");
if(cJSON_IsString(subSubobj_one)){
printf("%s:%s\n","Street",cJSON_GetStringValue(subSubobj_one));
}
cJSON *subSubobj_two = cJSON_GetObjectItem(subObj_four,"City");
if(cJSON_IsString(subSubobj_two)){
printf("%s:%s\n","City",cJSON_GetStringValue(subSubobj_two));
}
cJSON *subSubobj_three = cJSON_GetObjectItem(subObj_four,"Country");
if(cJSON_IsString(subSubobj_three)){
printf("%s:%s\n","Country",cJSON_GetStringValue(subSubobj_three));
}
}
cJSON *subArr_one = cJSON_GetObjectItem(json_root,"Phone numbers");
if(cJSON_IsArray(subArr_one)){
//子 JSON 项是数组
int array_size = cJSON_GetArraySize(subArr_one);
for(int i=0; i< array_size; i++){
cJSON *arrItem = cJSON_GetArrayItem(subArr_one,i);
//用 cJSON 自定义的宏判断 JSON 类型
if(arrItem->type == cJSON_String){
printf("%s:%s\n","Phone number1",arrItem->valuestring);
}
if(arrItem->type == cJSON_Number){
printf("%s:%d\n","Phone number2",arrItem->valueint);
}
}
}
}else if(cJSON_IsArray(json_root)){
//JSON根数据是对象
//和上面类似,根据已知的 JSON 文档内容调用相应 cJSON API 无限套娃
}
if(json_root){
//一定要记得释放内存
cJSON_Delete(json_root);
free(jsonData);
}
}
效果图如下
总结
- 开发环境是 VsCode,如何配置其开发环境看这篇文章 【C/C++】VS Code中C/C++环境搭建
- 相关 JSON 知识可看这篇文章 【Qt专栏】JSON知识储备
- 以上是针对cJSON API的学习总结,可能不太完善,后续会完善文章内容的!!!