当前位置: 首页 > news >正文

使用cJosn将数据读写文件

本篇来介绍如何将json数据写入文件,并支持对json文件中的字段进行修改。

1 cJSON

本篇使用cJSON来演示,cJSON 是一个轻量级的 C 语言 JSON 解析库,API 简洁易用,核心功能围绕 JSON 的创建、解析、修改和序列化展开。

需要先下载cJSON库:https://github.com/DaveGamble/cJSON

只需要引入两个文件:

  • cJSON.c
  • cJSON.h

使用cJSON来操作 json数据,需要先了解cJSON的API接口。

1.1 cJSON常用API

1.1.1 json对象 / 数组的创建

API 函数功能说明
cJSON *cJSON_CreateObject(void)创建一个空的 JSON 对象({}),返回指向该对象的指针
cJSON *cJSON_CreateArray(void)创建一个空的 JSON 数组([]),返回指向该数组的指针
cJSON *cJSON_CreateString(const char *string)创建一个字符串类型的 JSON 元素(如 "name": "张三" 中的值)
cJSON *cJSON_CreateNumber(double num)创建一个数字类型的 JSON 元素(支持整数、浮点数)
cJSON *cJSON_CreateBool(cJSON_bool boolean)创建一个布尔类型的 JSON 元素(truefalse,参数为 10
cJSON *cJSON_CreateNull(void)创建一个 null 类型的 JSON 元素

1.1.2 向对象 / 数组添加元素

API 函数功能说明
void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)向 JSON 对象添加一个键值对(string 为键,item 为值)
void cJSON_AddItemToArray(cJSON *array, cJSON *item)向 JSON 数组添加一个元素(无需键,按顺序排列)
cJSON *cJSON_AddStringToObject(cJSON *object, const char *name, const char *string)****向对象添加字符串类型的键值对(内部自动创建字符串元素)
cJSON *cJSON_AddNumberToObject(cJSON *object, const char *name, double number)向对象添加数字类型的键值对
cJSON *cJSON_AddBoolToObject(cJSON *object, const char *name, cJSON_bool boolean)向对象添加布尔类型的键值对

1.1.3 JSON 解析(从字符串到对象)

API 函数功能说明
cJSON *cJSON_Parse(const char *value)解析 JSON 字符串,返回根对象 / 数组指针。若解析失败,返回 NULL
const char *cJSON_GetErrorPtr(void)cJSON_Parse 失败时,调用此函数获取错误位置的描述(辅助调试)

1.1.4 读取 JSON 元素(获取字段值)

API 函数功能说明
cJSON *cJSON_GetObjectItem(const cJSON *object, const char *string)从 JSON 对象中获取指定键对应的元素(返回元素指针,若不存在则为 NULL
cJSON *cJSON_GetArrayItem(const cJSON *array, int index)从 JSON 数组中获取指定索引(index)的元素(索引从 0 开始)
int cJSON_GetArraySize(const cJSON *array)获取 JSON 数组的长度(元素个数)
const char *cJSON_GetStringValue(const cJSON *item)从字符串类型的元素中获取字符串值(需先确认元素类型为 cJSON_String
double cJSON_GetNumberValue(const cJSON *item)从数字类型的元素中获取数值(需先确认元素类型为 cJSON_Number
cJSON_bool cJSON_IsBool(const cJSON *item)判断元素是否为布尔类型(返回 1 是,0 否)
cJSON_bool cJSON_IsNull(const cJSON *item)判断元素是否为 null 类型

1.1.5 修改 JSON 元素

API 函数功能说明
void cJSON_SetValuestring(cJSON *item, const char *string)将元素的值修改为字符串(需元素原本为字符串类型,或强制覆盖)
void cJSON_SetNumberValue(cJSON *item, double number)将元素的值修改为数字
void cJSON_SetBoolValue(cJSON *item, cJSON_bool boolean)将元素的值修改为布尔值

1.1.6 JSON 序列化(从对象到字符串)

API 函数功能说明
char *cJSON_Print(const cJSON *item)将 JSON 对象 / 数组转换为带缩进的格式化字符串(可读性好,体积较大)
char *cJSON_PrintUnformatted(const cJSON *item)转换为无缩进的紧凑字符串(体积小,适合传输)
char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)带缓冲的序列化,prebuffer 为预分配缓冲区大小,fmt1 时格式化

1.1.7 内存释放

API 函数功能说明
void cJSON_Delete(cJSON *item)递归释放一个 JSON 对象 / 数组及其所有子元素占用的内存(根对象释放后,整个结构都被释放)

1.1.8 其它

API 函数功能说明
cJSON *cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)复制一个 JSON 元素(recurse=1 时递归复制子元素)。
void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)替换对象中指定键的元素(旧元素会被自动释放)。
void cJSON_ReplaceItemInArray(cJSON *array, int index, cJSON *newitem)替换数组中指定索引的元素。

1.2 创建json示例

这里示例创建一个json对象,并添加一些不同类型的字段:

  • cJSON_CreateObject:创建json对象
  • cJSON_AddStringToObject:添加字符串类型的数据
  • cJSON_AddNumberToObject:添加数值类型的数据
  • cJSON_AddBoolToObject:添加BOOL类型的数据
int test_create_a_json_object(char **json_str)
{// 创建JSONcJSON *root = cJSON_CreateObject();if (root == NULL) {PRINT("cJSON_CreateObject err!\n");return -1;}// 向根对象添加字段(支持字符串、数字、布尔等类型)cJSON_AddStringToObject(root, "name", "张三");    // 字符串字段cJSON_AddNumberToObject(root, "age", 22);        // 数字字段cJSON_AddBoolToObject(root, "is_student", 1);    // 布尔字段(0=false,1=true)cJSON_AddStringToObject(root, "major", "计算机科学"); // 待修改的示例字段// 将JSON对象转换为格式化字符串(带缩进,便于阅读)*json_str = cJSON_Print(root);if (json_str == NULL) {PRINT("cJSON_Print err!\n");cJSON_Delete(root); // 释放JSON对象内存,避免泄漏return -1;}PRINT("json_str:%s\n", *json_str);cJSON_Delete(root);return 0;
}

运行结果

[test_create_a_json_object][212] json_str:{"name":	"张三","age":	22,"is_student":	true,"major":	"计算机科学"
}

2 文件操作

创建json数据后,如果想将其写入文件,可以先将json数据转换为字符串(cJSON_Print),然后再将其整个写入文件。

2.1 写入文件

// 将JSON数据写入文件
int json_write_to_file(const char *filename, char *json_str) 
{if (NULL == filename || NULL == json_str){PRINT("NULL ptr\n");return -1;}// 打开文件("w"模式:覆盖写入,若文件不存在则创建)FILE *fp = fopen(filename, "w");if (fp == NULL) {PRINT("fopen %s err!\n", filename);return -1;}// 写入JSON字符串到文件fprintf(fp, "%s", json_str);// 释放资源fclose(fp);return 0;
}

2.2 修改json文件中的值

对于写入文件中的json数据,如果想要修改json中的数据,思路如下:

  • 先将json数据从文件中整个读出来
  • 然后对json数据进行解析(cJSON_Parse)
  • 接着查找到要修改的字段,进行修改
  • 最后再将整个json数据写回文件

对文件的读写的操作如下,函数的参数:

  • const char *filename:要操作的json文件的指针
  • const char *field_name:要修改的字段名称
  • const char *new_value:要修改为的值
// 修改文件中JSON的指定字段(支持字符串/数字/布尔类型)
int jsonfile_modify_field(const char *filename, const char *field_name, const char *new_value) 
{// 打开文件FILE *fp = fopen(filename, "r");if (fp == NULL) {PRINT("fopen %s err!\n", filename);return -1;}// 获取文件长度(用于分配缓冲区)fseek(fp, 0, SEEK_END);long file_len = ftell(fp);fseek(fp, 0, SEEK_SET);// 分配缓冲区(+1 用于存储字符串结束符 '\0')char *buffer = (char *)malloc(file_len + 1);if (buffer == NULL) {PRINT("malloc err!\n");fclose(fp);return -1;}// 读取文件内容到缓冲区fread(buffer, 1, file_len, fp);buffer[file_len] = '\0'; // 手动添加字符串结束符fclose(fp);// 解析缓冲区中的JSON字符串cJSON *root = cJSON_Parse(buffer);free(buffer); // 缓冲区已用完,释放内存if (root == NULL) {PRINT("cJSON_Parse err!\n");return -1;}// 修改JSON字段if (0 != json_modify_field(root, field_name, new_value)){PRINT("json_modify_field err!\n");cJSON_Delete(root);return -1;}// 将修改后的JSON重新写入文件(覆盖原内容)char *modified_json = cJSON_Print(root);if (modified_json == NULL) {PRINT("modify err!\n");cJSON_Delete(root);return -1;}// 以"w"模式打开文件(覆盖原内容)fp = fopen(filename, "w");if (fp == NULL) {PRINT("fopen %s err!\n", filename);free(modified_json);cJSON_Delete(root);return -1;}fprintf(fp, "%s", modified_json);PRINT("modify [%s] -> [%s] ok,now:\n%s\n", field_name, new_value, modified_json);// 释放所有资源fclose(fp);free(modified_json);cJSON_Delete(root);return 0;
}

具体的对json字段进行修改的逻辑,单独封装为json_modify_field

函数的参数:

  • cJSON *root:要操作的json指针
  • const char *field_name:要修改的字段名称
  • const char *new_value:要修改为的值

这里用到的API接口

  • cJSON_GetObjectItem:从 JSON 对象中获取指定键对应的元素,另外通过type还可判断字段的类型
  • 对字段的值进行修改:
    • cJSON_SetValuestring
    • cJSON_SetNumberValue
    • cJSON_SetBoolValue
// 修改JSON的指定字段(支持字符串/数字/布尔类型)
int json_modify_field(cJSON *root, const char *field_name, const char *new_value) 
{// 查找指定字段,若存在则修改;若不存在则提示cJSON *target_field = cJSON_GetObjectItem(root, field_name);if (target_field == NULL) {PRINT("no find:%s\n", field_name);return -1;}// 获取原字段类型并修改int modify_ok = 0;switch (target_field->type) {// 原字段是字符串:直接用新值替换case cJSON_String:{cJSON_SetValuestring(target_field, new_value);modify_ok = 1;break;}// 原字段是数字:尝试将 new_value 转为数字case cJSON_Number:{char *endptr;double num_val = strtod(new_value, &endptr);// 检查转换是否成功(new_value 必须全是数字)if (*endptr == '\0') { // 没有多余字符,转换有效cJSON_SetNumberValue(target_field, num_val);modify_ok = 1;} else {PRINT("new value [%s] convert to num err\n", new_value);}break;}// 原字段是布尔值:将 new_value 转为 0(false)或 1(true)case cJSON_True:case cJSON_False:{// 支持 "0"/"false" 转为 false;"1"/"true" 转为 true(不区分大小写)if (strcmp(new_value, "0") == 0 || strcasecmp(new_value, "false") == 0) {cJSON_SetBoolValue(target_field, 0);modify_ok = 1;} else if (strcmp(new_value, "1") == 0 || strcasecmp(new_value, "true") == 0) {cJSON_SetBoolValue(target_field, 1);modify_ok = 1;} else {PRINT("new value [%s] convert to bool err\n", new_value);}break;}default:{// 不支持的类型(如数组、对象等)PRINT("err type: %d\n", target_field->type);break;}}if (!modify_ok) {return -1;}return 0;
}

3 整体测试

下面是整体测试的主函数,基本流程为:

  • 创建json数据
  • 写入文件
  • 依次修改josn文件中不同类型的数据

在修改后,对文件的josn数据进行打印

// gcc test1.c cjson/cJSON.c -o test1 -lm
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "cjson/cJSON.h"#define PRINT(fmt, ...) printf("[%s][%d] " fmt, __func__, __LINE__, ##__VA_ARGS__)int main() 
{const char *filename = "user_info.json"; // 目标JSON文件PRINT("filename:%s\n", filename);char *json_str = NULL;if (0 != test_create_a_json_object(&json_str)){PRINT("test_create_a_json_object err!\n");return -1;}// 将JSON写入文件if (json_write_to_file(filename, json_str) != 0) {PRINT("json_write_to_file err!\n");return -1;}free(json_str);// 修改指定字段("age" 为 25)jsonfile_modify_field(filename, "age", "25");// 修改指定字段("is_srudent" 为 false)jsonfile_modify_field(filename, "is_student", "false");// 修改指定字段("major" 为 "嵌入式软件")jsonfile_modify_field(filename, "major", "嵌入式软件");return 0;
}

实际运行结果如下:

4 总结

本篇介绍了如何使用cJSON库以及借助文件操作,将json数据写入文件,并支持对文件中的json数据进行按字段的指定修改。

http://www.dtcms.com/a/554100.html

相关文章:

  • 做软件搜狗seo软件
  • 仿土巴兔网站建设学院网站建设流程
  • DeerFlow多智能体项目分析-向量数据库实现知识检索的源码解析
  • 001前端查询组件
  • AI在线客服搭建实战指南:三步构建7×24小时智能服务系统
  • TSMaster常用函数
  • 伯位数智模式为商家经营带来的变革与机遇
  • 网盘怎么做电影网站网站在公司做有什么要求吗
  • 介绍一下 multiprocessing 的 Manager模块
  • 网页建站总结报告网站建设初期怎么添加内容
  • C语言——猜数字游戏(rand、srand、time函数学习)
  • 多媒体网站开发实战装修设计软件免费
  • Rust流程控制(下):loop、while、for循环
  • 使用 UV 工具管理 Python 项目的常用命令
  • 解析视频汇聚平台EasyCVR强大的设备统一管理能力,助力构筑安防融合感知的基石
  • 南通做网站的手机怎么看网页源代码
  • 温州网上推广什么网站好深圳网络推广团队
  • 1951-2024年我国逐日\逐月\逐年近地面气温栅格数据
  • Linux----进程控制
  • 公司网站建设公司微网站建设价格
  • AI代码开发宝库系列:RAG--GraphRAG实战
  • 做一份网站动态图多少钱免费ip地址
  • 基于空间螺旋运动假设的水星近日点进动理论推导与验证
  • 手写Spring第20弹:JDK动态代理:深入剖析Java代理模式
  • 京网站建设公司行业app开发公司
  • 平面设计网站导航dw软件代码大全
  • PyTorch生成式人工智能——MUNIT详解与实现
  • 建设微网站网站公司介绍模板
  • 网站为什么做微云的采集备案网站首页地址
  • [linux] rm命令