JSON格式,C语言自己实现,以及直接调用库函数(一)
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。以下为你提供不同场景下常见的 JSON 格式示例。
1. 简单对象
JSON 对象是由键值对组成,用花括号 {} 包裹,键和值之间用冒号 : 分隔,多个键值对之间用逗号 , 分隔。
{
"name": "John Doe",
"age": 30,
"isStudent": false,
"hometown": null
}
2. 嵌套对象
JSON 对象可以嵌套,即一个对象的键对应的值可以是另一个对象。
json
{
"person": {
"name": "Alice",
"age": 25,
"contact": {
"email": "alice@example.com",
"phone": "123-456-7890"
}
}
}
3. 数组
JSON 数组是由值组成的有序列表,用方括号 [] 包裹,值之间用逗号 , 分隔。数组中的值可以是不同的数据类型,也可以是对象或数组。
[
"apple",
"banana",
"cherry"
]
4. 对象数组
数组中的元素可以是 JSON 对象。
[
{
"id": 1,
"name": "Product A",
"price": 19.99
},
{
"id": 2,
"name": "Product B",
"price": 29.99
}
]
5. 复杂嵌套结构
结合对象和数组可以形成更复杂的嵌套结构。
{
"employees": [
{
"name": "Bob",
"department": "Sales",
"projects": [
{
"projectName": "Project X",
"startDate": "2023-01-01"
},
{
"projectName": "Project Y",
"startDate": "2023-06-01"
}
]
},
{
"name": "Eve",
"department": "Marketing",
"projects": [
{
"projectName": "Project Z",
"startDate": "2023-03-01"
}
]
}
]
}
6. 包含不同数据类型的对象
{
"title": "Sample Document",
"author": {
"firstName": "Jane",
"lastName": "Smith"
},
"tags": ["document", "sample"],
"views": 1234,
"isPublished": true
}
二、
如果没有现成的 JSON 库,要自己实现 JSON 数据的解析和生成,可以按照 JSON 数据的结构特点,通过字符串处理来完成。以下分别介绍如何手动实现 JSON 对象和数组的解析与生成。
1. JSON 解析
解析思路
JSON 对象:JSON 对象由键值对组成,键和值之间用冒号 : 分隔,键值对之间用逗号 , 分隔,整体用花括号 {} 包裹。解析时需要识别键和值,处理嵌套对象和数组。
JSON 数组:JSON 数组由值组成,值之间用逗号 , 分隔,整体用方括号 [] 包裹。解析时需要逐个提取数组元素。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 跳过空白字符
void skip_whitespace(const char **json) {
while (**json == ' ' || **json == '\t' || **json == '\n' || **json == '\r') {
(*json)++;
}
}
// 解析字符串
char *parse_string(const char **json) {
(*json)++; // 跳过起始的双引号
const char *start = *json;
while (**json != '\0' && **json != '"') {
(*json)++;
}
size_t len = *json - start;
char *str = (char *)malloc(len + 1);
if (str == NULL) {
return NULL;
}
memcpy(str, start, len);
str[len] = '\0';
(*json)++; // 跳过结束的双引号
return str;
}
// 解析数字
int parse_number(const char **json) {
int num = 0;
while (**json >= '0' && **json <= '9') {
num = num * 10 + (**json - '0');
(*json)++;
}
return num;
}
// 解析 JSON 对象
void parse_object(const char **json) {
(*json)++; // 跳过起始的花括号
skip_whitespace(json);
while (**json != '}') {
char *key = parse_string(json);
skip_whitespace(json);
(*json)++; // 跳过冒号
skip_whitespace(json);
if (**json == '"') {
char *value = parse_string(json);
printf("Key: %s, Value: %s\n", key, value);
free(value);
} else if (**json >= '0' && **json <= '9') {
int value = parse_number(json);
printf("Key: %s, Value: %d\n", key, value);
}
free(key);
skip_whitespace(json);
if (**json == ',') {
(*json)++;
skip_whitespace(json);
}
}
(*json)++; // 跳过结束的花括号
}
// 解析 JSON 数组
void parse_array(const char **json) {
(*json)++; // 跳过起始的方括号
skip_whitespace(json);
while (**json != ']') {
if (**json == '"') {
char *value = parse_string(json);
printf("Array value: %s\n", value);
free(value);
} else if (**json >= '0' && **json <= '9') {
int value = parse_number(json);
printf("Array value: %d\n", value);
}
skip_whitespace(json);
if (**json == ',') {
(*json)++;
skip_whitespace(json);
}
}
(*json)++; // 跳过结束的方括号
}
// 主解析函数
void parse_json(const char *json) {
skip_whitespace(&json);
if (*json == '{') {
parse_object(&json);
} else if (*json == '[') {
parse_array(&json);
}
}
int main() {
const char *json_str = "{\"name\": \"John\", \"age\": 30}";
parse_json(json_str);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 生成 JSON 字符串表示的对象
char *generate_json_object(const char *key, const char *value) {
size_t key_len = strlen(key);
size_t value_len = strlen(value);
size_t json_len = 2 + key_len + 2 + 1 + 2 + value_len + 2; // {} "" : ""
char *json = (char *)malloc(json_len);
if (json == NULL) {
return NULL;
}
sprintf(json, "{\"%s\": \"%s\"}", key, value);
return json;
}
// 生成 JSON 字符串表示的数组
char *generate_json_array(const char **values, int count) {
size_t total_len = 2; // []
for (int i = 0; i < count; i++) {
total_len += strlen(values[i]) + 2; // ""
if (i < count - 1) {
total_len++; // ,
}
}
char *json = (char *)malloc(total_len);
if (json == NULL) {
return NULL;
}
json[0] = '[';
size_t index = 1;
for (int i = 0; i < count; i++) {
json[index++] = '"';
strcpy(json + index, values[i]);
index += strlen(values[i]);
json[index++] = '"';
if (i < count - 1) {
json[index++] = ',';
}
}
json[index] = ']';
json[index + 1] = '\0';
return json;
}
int main() {
const char *key = "name";
const char *value = "John";
char *json_obj = generate_json_object(key, value);
if (json_obj != NULL) {
printf("JSON object: %s\n", json_obj);
free(json_obj);
}
const char *values[] = {"apple", "banana", "cherry"};
int count = sizeof(values) / sizeof(values[0]);
char *json_arr = generate_json_array(values, count);
if (json_arr != NULL) {
printf("JSON array: %s\n", json_arr);
free(json_arr);
}
return 0;
}
2
{
"employees": [
{
"name": "Bob",
"department": "Sales",
"projects": [
{
"projectName": "Project X",
"startDate": "2023-01-01"
},
{
"projectName": "Project Y",
"startDate": "2023-06-01"
}
]
},
{
"name": "Eve",
"department": "Marketing",
"projects": [
{
"projectName": "Project Z",
"startDate": "2023-03-01"
}
]
}
]
}
下面是解析该 JSON 数据的 C 语言代码:
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
int main() {
const char *json_str = "{\"employees\": [{\"name\": \"Bob\", \"department\": \"Sales\", \"projects\": [{\"projectName\": \"Project X\", \"startDate\": \"2023-01-01\"}, {\"projectName\": \"Project Y\", \"startDate\": \"2023-06-01\"}]}, {\"name\": \"Eve\", \"department\": \"Marketing\", \"projects\": [{\"projectName\": \"Project Z\", \"startDate\": \"2023-03-01\"}]}]}";
// 解析 JSON 字符串
cJSON *root = cJSON_Parse(json_str);
if (root == NULL) {
const char *error_ptr = cJSON_GetErrorPtr();
if (error_ptr != NULL) {
fprintf(stderr, "Error before: %s\n", error_ptr);
}
return 1;
}
// 获取 employees 数组
cJSON *employees = cJSON_GetObjectItem(root, "employees");
if (cJSON_IsArray(employees)) {
int array_size = cJSON_GetArraySize(employees);
for (int i = 0; i < array_size; i++) {
cJSON *employee = cJSON_GetArrayItem(employees, i);
cJSON *name = cJSON_GetObjectItem(employee, "name");
cJSON *department = cJSON_GetObjectItem(employee, "department");
if (cJSON_IsString(name) && cJSON_IsString(department)) {
printf("Employee Name: %s\n", name->valuestring);
printf("Department: %s\n", department->valuestring);
}
// 获取 projects 数组
cJSON *projects = cJSON_GetObjectItem(employee, "projects");
if (cJSON_IsArray(projects)) {
int project_size = cJSON_GetArraySize(projects);
printf("Projects:\n");
for (int j = 0; j < project_size; j++) {
cJSON *project = cJSON_GetArrayItem(projects, j);
cJSON *projectName = cJSON_GetObjectItem(project, "projectName");
cJSON *startDate = cJSON_GetObjectItem(project, "startDate");
if (cJSON_IsString(projectName) && cJSON_IsString(startDate)) {
printf(" - Project Name: %s\n", projectName->valuestring);
printf(" Start Date: %s\n", startDate->valuestring);
}
}
}
printf("\n");
}
}
// 释放 cJSON 对象占用的内存
cJSON_Delete(root);
return 0;
}
- 生成 JSON 数据
下面的代码展示了如何使用 cJSON 库生成一个包含不同数据类型的 JSON 对象:
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
int main() {
// 创建根 JSON 对象
cJSON *root = cJSON_CreateObject();
if (root == NULL) {
fprintf(stderr, "Failed to create JSON object\n");
return 1;
}
// 添加字符串类型的键值对
cJSON_AddStringToObject(root, "title", "Sample Document");
// 创建嵌套的 author 对象
cJSON *author = cJSON_CreateObject();
if (author == NULL) {
fprintf(stderr, "Failed to create author object\n");
cJSON_Delete(root);
return 1;
}
cJSON_AddStringToObject(author, "firstName", "Jane");
cJSON_AddStringToObject(author, "lastName", "Smith");
cJSON_AddItemToObject(root, "author", author);
// 创建 tags 数组
cJSON *tags = cJSON_CreateArray();
if (tags == NULL) {
fprintf(stderr, "Failed to create tags array\n");
cJSON_Delete(root);
return 1;
}
cJSON_AddItemToArray(tags, cJSON_CreateString("document"));
cJSON_AddItemToArray(tags, cJSON_CreateString("sample"));
cJSON_AddItemToObject(root, "tags", tags);
// 添加数字类型的键值对
cJSON_AddNumberToObject(root, "views", 1234);
// 添加布尔类型的键值对
cJSON_AddBoolToObject(root, "isPublished", 1);
// 将 JSON 对象转换为字符串
char *json_str = cJSON_Print(root);
if (json_str == NULL) {
fprintf(stderr, "Failed to print JSON object\n");
cJSON_Delete(root);
return 1;
}
// 打印 JSON 字符串
printf("%s\n", json_str);
// 释放内存
free(json_str);
cJSON_Delete(root);
return 0;
}
下面为你展示如何使用 C 语言结合 cJSON 库,以文件形式读写和保存 JSON 数据。我们会提供两个示例,一个是从文件中读取 JSON 数据并解析,另一个是将生成的 JSON 数据保存到文件中。
1. 从文件读取并解析 JSON 数据
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cJSON.h"
// 从文件读取内容到字符串
char* read_file(const char* filename) {
FILE* file = fopen(filename, "r");
if (file == NULL) {
perror("Failed to open file");
return NULL;
}
// 获取文件大小
fseek(file, 0, SEEK_END);
long size = ftell(file);
fseek(file, 0, SEEK_SET);
// 分配内存来存储文件内容
char* buffer = (char*)malloc(size + 1);
if (buffer == NULL) {
perror("Failed to allocate memory");
fclose(file);
return NULL;
}
// 读取文件内容
fread(buffer, 1, size, file);
buffer[size] = '\0';
fclose(file);
return buffer;
}
int main() {
const char* filename = "input.json";
char* json_str = read_file(filename);
if (json_str == NULL) {
return 1;
}
// 解析 JSON 字符串
cJSON* root = cJSON_Parse(json_str);
if (root == NULL) {
const char* error_ptr = cJSON_GetErrorPtr();
if (error_ptr != NULL) {
fprintf(stderr, "Error before: %s\n", error_ptr);
}
free(json_str);
return 1;
}
// 示例:获取并打印 "name" 字段的值
cJSON* name = cJSON_GetObjectItem(root, "name");
if (cJSON_IsString(name)) {
printf("Name: %s\n", name->valuestring);
}
// 释放资源
free(json_str);
cJSON_Delete(root);
return 0;
}
2. 生成 JSON 数据并保存到文件
#include <stdio.h>
#include <stdlib.h>
#include "cJSON.h"
int main() {
// 创建根 JSON 对象
cJSON* root = cJSON_CreateObject();
if (root == NULL) {
fprintf(stderr, "Failed to create JSON object\n");
return 1;
}
// 添加键值对
cJSON_AddStringToObject(root, "name", "John Doe");
cJSON_AddNumberToObject(root, "age", 30);
// 将 JSON 对象转换为字符串
char* json_str = cJSON_Print(root);
if (json_str == NULL) {
fprintf(stderr, "Failed to print JSON object\n");
cJSON_Delete(root);
return 1;
}
// 打开文件以写入模式
FILE* file = fopen("output.json", "w");
if (file == NULL) {
perror("Failed to open file");
free(json_str);
cJSON_Delete(root);
return 1;
}
// 将 JSON 字符串写入文件
fputs(json_str, file);
// 关闭文件
fclose(file);
// 释放内存
free(json_str);
cJSON_Delete(root);
return 0;
}