cJSON 使用方法详解
cJSON 是一个轻量级的 C 语言 JSON 解析器和生成器库,非常适合嵌入式系统和资源受限环境。以下是 cJSON 的详细使用方法。
1. 安装与集成
下载 cJSON
可以直接从 GitHub 获取源码:
git clone https://github.com/DaveGamble/cJSON.git
集成到项目
将 cJSON.h
和 cJSON.c
复制到你的项目中,或者编译为静态库:
cd cJSON mkdir build cd build cmake .. make sudo make install # 安装到系统
2. 基本用法
创建 JSON 对象
#include <stdio.h> #include <stdlib.h> #include "cJSON.h" int main() { // 创建根对象 cJSON *root = cJSON_CreateObject(); // 添加基本类型 cJSON_AddStringToObject(root, "name", "John Doe"); cJSON_AddNumberToObject(root, "age", 30); cJSON_AddBoolToObject(root, "is_student", 0); // 0=false, 1=true // 添加数组 cJSON *courses = cJSON_CreateArray(); cJSON_AddItemToArray(courses, cJSON_CreateString("Math")); cJSON_AddItemToArray(courses, cJSON_CreateString("Physics")); cJSON_AddItemToObject(root, "courses", courses); // 添加嵌套对象 cJSON *address = cJSON_CreateObject(); cJSON_AddStringToObject(address, "city", "New York"); cJSON_AddStringToObject(address, "zip", "10001"); cJSON_AddItemToObject(root, "address", address); // 转换为字符串并打印 char *json_str = cJSON_Print(root); printf("Generated JSON:\n%s\n", json_str); // 释放内存 free(json_str); cJSON_Delete(root); return 0; }
解析 JSON 字符串
#include <stdio.h> #include <stdlib.h> #include "cJSON.h" int main() { const char *json_string = "{\"name\":\"Alice\",\"age\":25,\"is_student\":true,\"courses\":[\"Art\",\"History\"]}"; // 解析JSON字符串 cJSON *root = cJSON_Parse(json_string); if (root == NULL) { const char *error_ptr = cJSON_GetErrorPtr(); if (error_ptr != NULL) { fprintf(stderr, "Error before: %s\n", error_ptr); } return 1; } // 获取值 cJSON *name = cJSON_GetObjectItemCaseSensitive(root, "name"); cJSON *age = cJSON_GetObjectItemCaseSensitive(root, "age"); cJSON *is_student = cJSON_GetObjectItemCaseSensitive(root, "is_student"); cJSON *courses = cJSON_GetObjectItemCaseSensitive(root, "courses"); // 打印值 printf("Name: %s\n", name->valuestring); printf("Age: %d\n", age->valueint); printf("Is student: %s\n", cJSON_IsTrue(is_student) ? "true" : "false"); // 遍历数组 printf("Courses:\n"); cJSON *course = NULL; cJSON_ArrayForEach(course, courses) { printf("- %s\n", course->valuestring); } // 释放内存 cJSON_Delete(root); return 0; }
3. 文件读写
写入 JSON 文件
void write_json_file(const char *filename, cJSON *json) { FILE *fp = fopen(filename, "w"); if (fp == NULL) { perror("Failed to open file for writing"); return; } char *json_str = cJSON_Print(json); fputs(json_str, fp); fclose(fp); free(json_str); }
读取 JSON 文件
c
cJSON *read_json_file(const char *filename) { FILE *fp = fopen(filename, "r"); if (fp == NULL) { perror("Failed to open file for reading"); return NULL; } // 获取文件大小 fseek(fp, 0, SEEK_END); long length = ftell(fp); fseek(fp, 0, SEEK_SET); // 读取文件内容 char *buffer = malloc(length + 1); if (buffer == NULL) { fclose(fp); return NULL; } fread(buffer, 1, length, fp); buffer[length] = '\0'; fclose(fp); // 解析JSON cJSON *json = cJSON_Parse(buffer); free(buffer); return json; }
4. 高级用法
修改现有 JSON
void modify_json(cJSON *root) { // 修改现有值 cJSON *age = cJSON_GetObjectItemCaseSensitive(root, "age"); if (age != NULL) { age->valueint = 31; } // 添加新字段 cJSON_AddStringToObject(root, "email", "john@example.com"); // 删除字段 cJSON_DeleteItemFromObject(root, "is_student"); }
错误处理
cJSON *parse_json_with_error_handling(const char *json_string) { cJSON *json = cJSON_Parse(json_string); if (json == NULL) { const char *error_ptr = cJSON_GetErrorPtr(); if (error_ptr != NULL) { fprintf(stderr, "Error parsing JSON: %s\n", error_ptr); } return NULL; } return json; }
使用钩子自定义内存管理
c
// 自定义malloc/free函数 static void *custom_malloc(size_t size) { printf("Allocating %zu bytes\n", size); return malloc(size); } static void custom_free(void *ptr) { printf("Freeing memory at %p\n", ptr); free(ptr); } void use_custom_allocator() { // 设置自定义内存管理函数 cJSON_Hooks hooks; hooks.malloc_fn = custom_malloc; hooks.free_fn = custom_free; cJSON_InitHooks(&hooks); // 现在cJSON会使用自定义的内存管理 cJSON *root = cJSON_CreateObject(); cJSON_AddStringToObject(root, "test", "value"); cJSON_Delete(root); }
5. 性能优化技巧
使用缓冲打印:
char buffer[1024]; cJSON_PrintPreallocated(root, buffer, sizeof(buffer), 0);
避免频繁分配:重用 cJSON 对象
使用
cJSON_PrintUnformatted
节省空间:char *compact_json = cJSON_PrintUnformatted(root);
批量操作:减少单独的添加操作
6. 完整示例
#include <stdio.h> #include <stdlib.h> #include "cJSON.h" int main() { // 1. 创建JSON cJSON *root = cJSON_CreateObject(); cJSON_AddStringToObject(root, "name", "John Smith"); cJSON_AddNumberToObject(root, "age", 35); cJSON *address = cJSON_CreateObject(); cJSON_AddStringToObject(address, "street", "123 Main St"); cJSON_AddStringToObject(address, "city", "Boston"); cJSON_AddItemToObject(root, "address", address); cJSON *phones = cJSON_CreateArray(); cJSON_AddItemToArray(phones, cJSON_CreateString("555-1234")); cJSON_AddItemToArray(phones, cJSON_CreateString("555-5678")); cJSON_AddItemToObject(root, "phones", phones); // 2. 打印JSON char *json_str = cJSON_Print(root); printf("Generated JSON:\n%s\n", json_str); free(json_str); // 3. 写入文件 write_json_file("person.json", root); // 4. 从文件读取并修改 cJSON *from_file = read_json_file("person.json"); if (from_file != NULL) { cJSON *age = cJSON_GetObjectItemCaseSensitive(from_file, "age"); age->valueint += 1; cJSON_AddBoolToObject(from_file, "married", 1); char *modified_json = cJSON_Print(from_file); printf("Modified JSON:\n%s\n", modified_json); free(modified_json); cJSON_Delete(from_file); } // 清理 cJSON_Delete(root); return 0; }
7. 常见问题解决
内存泄漏:
确保为每个
cJSON_Create*
和cJSON_Print
调用相应的cJSON_Delete
和free
访问不存在的字段:
总是检查
cJSON_GetObjectItemCaseSensitive
的返回值是否为 NULL
类型错误:
使用
cJSON_IsString
,cJSON_IsNumber
等函数验证类型
大文件处理:
考虑流式解析或分块处理大JSON文件
cJSON 是一个简单但功能强大的库,适用于大多数C语言的JSON处理需求。通过合理的内存管理和错误处理,可以构建健壮的JSON处理代码。