cJSON 使用方法详解

发布于:2025-06-30 ⋅ 阅读:(14) ⋅ 点赞:(0)

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. 性能优化技巧

  1. 使用缓冲打印

    char buffer[1024];
    cJSON_PrintPreallocated(root, buffer, sizeof(buffer), 0);
  2. 避免频繁分配:重用 cJSON 对象

  3. 使用 cJSON_PrintUnformatted 节省空间:

    char *compact_json = cJSON_PrintUnformatted(root);
  4. 批量操作:减少单独的添加操作

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. 常见问题解决

  1. 内存泄漏

    • 确保为每个 cJSON_Create* 和 cJSON_Print 调用相应的 cJSON_Delete 和 free

  2. 访问不存在的字段

    • 总是检查 cJSON_GetObjectItemCaseSensitive 的返回值是否为 NULL

  3. 类型错误

    • 使用 cJSON_IsStringcJSON_IsNumber 等函数验证类型

  4. 大文件处理

    • 考虑流式解析或分块处理大JSON文件

cJSON 是一个简单但功能强大的库,适用于大多数C语言的JSON处理需求。通过合理的内存管理和错误处理,可以构建健壮的JSON处理代码。


网站公告

今日签到

点亮在社区的每一天
去签到