用代码详解使用从JSON库实现json文件的序列化和反序列化
了解json
Json入门教程:了解Json基本的概念
json数据类型
- number:和JavaScript的number完全一致;相当于C中的int类型
- boolean:就是JavaScript的true或false;相当于c++中的bool类型
- string:就是JavaScript的string;相当于c++的string类型
- null:就是JavaScript的null;相当于C的NULL类型
- array:就是JavaScript的Array表示方式——[];相当于C的数组
- object:就是JavaScript的{ … }表示方式。相当于C++的类或者C的结构体
注意:json的数据类型在源码实现中和具体的编程语言有关,比如boolean在C中并没有相应的类型,C相关的实现库可能会用0和1表示。也可以添加头文件#include<stdbool.h>
(不推荐)。
格式规范
- json以大括号起始和结尾
- 内容都是以键值对的形式存在
- 所有的键都是字符串
- 值的类型不一定,属于JavaScript 的基本数据类型
- 每个键值对以
,
分割 - 最后一个键值对不加逗号
{
"name": "小明",
"age": 14,
"gender": true,
"height": 1.65,
"grade": null,
"skills": [
"JavaScript",
"Java",
"Python",
"Lisp"
]
}
json格式校验
JSON基本操作
Json序列化:可以理解为利用程序生成Json字符串的过程。
Json反序列化:可以理解为利用程序将已有的Json字符串解析出我们需要的值的过程。
cJson
相关资料
cJSON的github地址(这个不用看,相当于官方源码地址)
github
cJSON 使用详解
https://blog.csdn.net/qq_32172673/article/details/88305781
JSON的简单介绍以及C语言的JSON库使用
https://www.cnblogs.com/liunianshiwei/p/6087596.html
关键接口梳理
/* 类型定义 */
#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
/* CJSON核心结构体 */
typedef struct cJSON {
struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
int type; /* 节点的类型,取值是上面的6种 */
char *valuestring; /* 如果类型是cJSON_String,那么值会被存到这里 */
int valueint; /* 如果类型是cJSON_Number,且是整型,那么值会被存到这里 */
double valuedouble; /* 如果类型是cJSON_Number,且是浮点型,那么值会被存到这里 */
char *string; /* 键*/
} cJSON;
/****************************通用接口****************************/
//把传入的字符串转成cJSON的结构(反序列化)
cJSON *cJSON_Parse(const char *value);
//把cJSON结构转成字符串(序列化),调用后需要配合free接口释放malloc的内存
char *cJSON_Print(cJSON *item);
//无格式化序列化,节省内存,调用后需要配合free接口释放malloc的内存
char *cJSON_PrintUnformatted(cJSON *item);
//释放节点的内存,防止内存泄露
void cJSON_Delete(cJSON *c);
/****************************反序列化相关接口****************************/
//获取数组的大小
int cJSON_GetArraySize(cJSON *array);
//从array数组中获取第item个子节点
cJSON *cJSON_GetArrayItem(cJSON *array,int item);
//获取object大节点名字叫string的子节点
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
//判断object大节点中是否有名字叫string的小节点
int cJSON_HasObjectItem(cJSON *object,const char *string);
/****************************序列化相关接口****************************/
//创建一个普通节点
cJSON *cJSON_CreateObject(void);
//创建一个数组节点
cJSON *cJSON_CreateArray(void);
//把item节点增加到array的数组节点中
void cJSON_AddItemToArray(cJSON *array, cJSON *item);
//把item节点增加到object中作为子节点,item节点的键名为string
void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
//创建各种类型的cJSON节点
cJSON *cJSON_CreateNull(void);
cJSON *cJSON_CreateTrue(void);
cJSON *cJSON_CreateFalse(void);
cJSON *cJSON_CreateBool(int b);
cJSON *cJSON_CreateNumber(double num);
cJSON *cJSON_CreateString(const char *string);
cJSON *cJSON_CreateArray(void);
cJSON *cJSON_CreateObject(void);
例子
反序列化
使用cJSON库对下面的JSON文件进行反序列化操作。ver和login的子节点直接打印即可,data的数据节点解析后形成链表存储(将下面内容存为文件,读取后解析即可)。
{
"ver": "1.0",
"login": {
"user": "zhangsan",
"pwd": 1234
},
"data": [{
"key": 1,
"type": 2,
"val": "10"
},
{
"key": 2,
"type": 1,
"val": "0"
},
{
"key": 3,
"type": 3,
"val": "22.5"
}
]
}
注意:上面的所有val值都是string类型,解析出来存到节点前,需要根据type的类型来进行转换,按照相应的类型存储到共用体中。
提示:对于数据解析后,形成新的节点存放链表,最好的方式是为每个节点分配单独的内存。例:
struct data {
int key;
int type;
union val_t val;
struct list_head list;
};
struct data *node = (struct data *)malloc(sizeof(struct data));
node->xxx = xxx;
插入链表即可
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "cJSON.h"
typedef union
{
bool bool_val;
int int_val;
float float_val;
} val_t;
typedef struct data
{
int key;
int type;
val_t val;
} data_t;
typedef struct node
{
data_t data;
struct node *next;
} node_t;
int main()
{
FILE *fp = fopen("item.json", "r");
if (!fp)
{
printf("Failed to open file\n");
return 1;
}
char buffer[1024];
fread(buffer, 1, sizeof(buffer), fp);
fclose(fp);
cJSON *root = cJSON_Parse(buffer);
if (!root)
{
printf("Failed to parse JSON: %s\n", cJSON_GetErrorPtr());
return 1;
}
cJSON *ver = cJSON_GetObjectItem(root, "ver");
if (ver && ver->type == cJSON_String)
{
printf("ver: %s\n", ver->valuestring);
}
cJSON *login = cJSON_GetObjectItem(root, "login");
if (login && login->type == cJSON_Object)
{
cJSON *user = cJSON_GetObjectItem(login, "user");
if (user && user->type == cJSON_String)
{
printf("login.user: %s\n", user->valuestring);
}
cJSON *pwd = cJSON_GetObjectItem(login, "pwd");
if (pwd && pwd->type == cJSON_Number)
{
printf("login.pwd: %d\n", pwd->valueint);
}
}
cJSON *data = cJSON_GetObjectItem(root, "data");
if (data && data->type == cJSON_Array)
{
int size = cJSON_GetArraySize(data);
node_t *head = NULL, *tail = NULL;
for (int i = 0; i < size; i++)
{
cJSON *item = cJSON_GetArrayItem(data, i);
if (item && item->type == cJSON_Object)
{
data_t *node_data = malloc(sizeof(data_t));
memset(node_data, 0, sizeof(data_t));
cJSON *key = cJSON_GetObjectItem(item, "key");
if (key && key->type == cJSON_Number)
{
node_data->key = key->valueint;
}
cJSON *type = cJSON_GetObjectItem(item, "type");
if (type && type->type == cJSON_Number)
{
node_data->type = type->valueint;
}
cJSON *val = cJSON_GetObjectItem(item, "val");
if (val)
{
switch (node_data->type)
{
case 1:
if (val->type == cJSON_String)
{
const char *val_str = val->valuestring;
node_data->val.bool_val = atoi(val_str);
}
break;
case 2:
if (val->type == cJSON_String)
{
const char *val_str = val->valuestring;
node_data->val.int_val = atoi(val_str);
}
break;
case 3:
if (val->type == cJSON_String)
{
const char *val_str = val->valuestring;
node_data->val.float_val = atof(val_str);
}
break;
}
}
node_t *node = malloc(sizeof(node_t));
node->data = *node_data;
node->next = NULL;
if (head == NULL)
{
head = node;
tail = node;
}
else
{
tail->next = node;
tail = node;
}
free(node_data);
}
}
cJSON_Delete(root);
node_t *node = head;
while (node)
{
printf("key: %d, type: %d, val: ", node->data.key, node->data.type);
switch (node->data.type)
{
case 1:
printf("%d\n", node->data.val.bool_val);
break;
case 2:
printf("%d\n", node->data.val.int_val);
break;
case 3:
printf("%.1f\n", node->data.val.float_val);
break;
}
node = node->next;
}
node = head;
while (node)
{
node_t *temp = node;
node = node->next;
free(temp);
}
return 0;
}
return 0;
}
序列化
使用cJSON库序列化出下面的JSON内容。
{
"name": "小明",
"age": 14,
"gender": true,
"height": 1.65,
"grade": null,
"skills": [
"JavaScript",
"Java",
"Python",
"Lisp"
]
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "cJSON.h"
#include <windows.h>
// {
// "name": "小明",
// "age": 14,
// "gender": true,
// "height": 1.65,
// "grade": null,
// "skills": [
// "JavaScript",
// "Java",
// "Python",
// "Lisp"
// ]
// }
int main()
{
SetConsoleOutputCP(CP_UTF8);
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "name", "小明");
cJSON_AddNumberToObject(root, "age", 14);
cJSON_AddBoolToObject(root, "gender", true);
cJSON_AddNumberToObject(root, "height", 1.65);
cJSON_AddNullToObject(root, "grade");
cJSON *skills = cJSON_CreateArray();
cJSON_AddItemToObject(root, "skills", skills);
cJSON_AddItemToArray(skills, cJSON_CreateString("JavaScript"));
cJSON_AddItemToArray(skills, cJSON_CreateString("Java"));
cJSON_AddItemToArray(skills, cJSON_CreateString("Python"));
cJSON_AddItemToArray(skills, cJSON_CreateString("Lisp"));
printf("%s\n", cJSON_Print(root));
cJSON_Delete(root);
return 0;
}
序列化和反序列化
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "cJSON.h"
#include <windows.h>
typedef union val_t
{
bool bool_val;
int int_val;
float float_val;
} val_t;
typedef struct data_t
{
int key;
int type;
val_t val;
} data_t;
int main(int argc, char const *argv[])
{
SetConsoleOutputCP(CP_UTF8);
// 反序列化
FILE *fp = fopen("item.json", "r");
char buffer[1024];
fread(buffer, 1, sizeof(buffer), fp);
fclose(fp);
cJSON *root = cJSON_Parse(buffer);
if (!root)
{
printf("Failed to parse JSON: %s\n", cJSON_GetErrorPtr());
return -1;
}
// 获取ver
cJSON *ver = cJSON_GetObjectItem(root, "ver");
if (ver && ver->type == cJSON_String)
{
printf("%s: %s\n", ver->string, ver->valuestring);
}
// 获取login
cJSON *login = cJSON_GetObjectItem(root, "login");
cJSON *user = cJSON_GetObjectItem(login, "user");
if (user && user->type == cJSON_String)
{
printf("%s: %s\n", user->string, user->valuestring);
}
cJSON *pwd = cJSON_GetObjectItem(login, "pwd");
if (pwd && pwd->type == cJSON_Number)
{
printf("%s: %d\n", pwd->string, pwd->valueint);
}
// 获取data
cJSON *data = cJSON_GetObjectItem(root, "data");
if (data && data->type == cJSON_Array)
{
int size = cJSON_GetArraySize(data);
data_t *items = malloc(size * sizeof(data_t));
memset(items, 0, size * sizeof(data_t));
for (int i = 0; i < size; i++)
{
cJSON *item = cJSON_GetArrayItem(data, i);
if (item && item->type == cJSON_Object)
{
cJSON *key = cJSON_GetObjectItem(item, "key");
if (key && key->type == cJSON_Number)
{
items[i].key = key->valueint;
}
cJSON *type = cJSON_GetObjectItem(item, "type");
if (type && type->type == cJSON_Number)
{
items[i].type = type->valueint;
}
cJSON *val = cJSON_GetObjectItem(item, "val");
if (val)
{
switch (items[i].type)
{
case 1:
case 2:
if (val->type == cJSON_String)
{
items[i].val.int_val = atoi(val->valuestring);
}
break;
case 3:
if (val->type == cJSON_String)
{
items[i].val.float_val = atof(val->valuestring);
}
break;
}
}
}
}
// Print the data items
for (int i = 0; i < size; i++)
{
printf("key: %d, type: %d, val: ", items[i].key, items[i].type);
switch (items[i].type)
{
case 1:
case 2:
printf("%d\n", items[i].val.int_val);
break;
case 3:
printf("%f\n", items[i].val.float_val);
break;
}
}
free(items);
}
cJSON_Delete(root);
// 序列化
cJSON *root1 = cJSON_CreateObject();
cJSON_AddStringToObject(root1, "name", "小明");
cJSON_AddNumberToObject(root1, "age", 14);
cJSON_AddBoolToObject(root1, "gender", true);
cJSON_AddNumberToObject(root1, "height", 1.65);
cJSON_AddNullToObject(root1, "grade");
cJSON *skills = cJSON_CreateArray();
cJSON_AddItemToObject(root1, "skills", skills);
cJSON_AddItemToArray(skills, cJSON_CreateString("JavaScript"));
cJSON_AddItemToArray(skills, cJSON_CreateString("Java"));
cJSON_AddItemToArray(skills, cJSON_CreateString("Python"));
cJSON_AddItemToArray(skills, cJSON_CreateString("Lisp"));
char *out = cJSON_Print(root1);
printf("%s\n", out);
free(out);
cJSON_Delete(root1);
return 0;
}
注意
编译cJSON库时候,gcc需要增加 -l m选项,动态链接math库。
gcc xxx.c -o xxx cJSON.c -lm