JsonCpp: 一个好用且轻量级的JSON解析库
目录
1.简介
2.安装与集成
2.1.包管理器安装(推荐 Linux/macOS)
2.2.源码集成(适合所有系统)
3.核心组件与接口
4.基本使用示例
5.高级用法
6.注意事项
7.总结
1.简介
JsonCpp 是一个功能完善的 C++ 库,用于解析、生成和操作 JSON(JavaScript Object Notation)数据。它遵循 JSON 标准,支持跨平台(Linux/macOS/Windows 等),且接口简洁,是 C++ 项目中处理 JSON 数据的常用选择。
它的特点有:
1.功能完整:支持 JSON 所有基础类型(字符串、数字、布尔、数组、对象、null),以及嵌套结构。
2.双接口设计:提供 “简单接口”(快速解析 / 生成)和 “高级接口”(自定义配置,如格式化、错误处理)。
3.跨平台:纯 C++ 实现,不依赖系统特定库,兼容主流编译器(GCC、Clang、MSVC)。
4.轻量易集成:可通过源码(单头文件 / 多文件)或包管理器快速集成到项目。
5.支持注释:可配置解析含注释的 JSON(非标准 JSON 扩展,实用但需显式开启)。
2.安装与集成
JsonCpp 在 CMake 项目中的集成主要有两种方式,需根据项目需求选择:
集成方式 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
1. 源码嵌入(Third-Party) | 需固定 JsonCpp 版本,避免依赖冲突 | 版本可控,无需额外安装 | 需手动配置 CMake 生成 config.h |
2. 包管理器安装(vcpkg) | 追求便捷,项目依赖统一管理 | 一键安装,CMake 自动查找 | 版本依赖包管理器,需联网 |
2.1.包管理器安装(推荐 Linux/macOS)
Ubuntu/Debian:
sudo apt-get install libjsoncpp-dev
macOS(Homebrew):
brew install jsoncpp
Windows(vcpkg):
若项目使用 vcpkg 管理依赖(如你之前用 vcpkg 安装 asio、openssl),可一键安装 JsonCpp 并通过 CMake 自动查找,无需手动处理源码和 config.h
。
步骤 1:用 vcpkg 安装 JsonCpp
打开 vcpkg 命令行,执行:
# 安装 JsonCpp(x64-windows 对应 64位,根据你的架构调整)
vcpkg install jsoncpp:x64-windows
步骤 2:CMake 配置(极简!)
在项目 CMakeLists.txt
中通过 find_package
自动查找 JsonCpp,无需手动处理源码:
cmake_minimum_required(VERSION 3.10)
project(JsonCppDemo)
set(CMAKE_CXX_STANDARD 11)# -------------------------- 关键:通过 vcpkg 查找 JsonCpp --------------------------
# 需确保 CMake 能找到 vcpkg 的包(通过 -DCMAKE_TOOLCHAIN_FILE 指定 vcpkg 工具链)
find_package(jsoncpp CONFIG REQUIRED)# -------------------------- 编译项目 --------------------------
add_executable(JsonCppDemo src/main.cpp)# -------------------------- 链接 JsonCpp 库 --------------------------
target_link_libraries(JsonCppDemo PRIVATE jsoncpp_lib) # 链接 JsonCpp 库
步骤 3:CMake 命令行指定 vcpkg 工具链
运行 CMake 时,需通过 -DCMAKE_TOOLCHAIN_FILE
告诉 CMake vcpkg 的工具链路径(否则找不到 JsonCpp):
# 替换为你的 vcpkg 工具链路径(通常是 vcpkg 安装目录下的 scripts/buildsystems/vcpkg.cmake)
cmake .. -G "Ninja" -DCMAKE_TOOLCHAIN_FILE="C:/Users/Administrator/vcpkg/scripts/buildsystems/vcpkg.cmake" -A x64
2.2.源码集成(适合所有系统)
适合将 JsonCpp 源码放在项目 third_party/Json
目录下(如你之前的 third_party/Json
路径),需手动配置 CMake 生成关键文件(如 config.h
)。
步骤 1:准备 JsonCpp 源码
1.从 JsonCpp 官方仓库 下载源码(推荐 1.9.x 稳定版);
2.解压后将核心目录 src/lib_json
和头文件目录 include/json
复制到项目的 third_party/Json
下,最终目录结构如下:
你的项目根目录/
├── third_party/
│ └── Json/
│ ├── include/ # JsonCpp 头文件目录
│ │ └── json/
│ │ ├── json.h # 核心头文件
│ │ └── reader.h # 解析相关头文件
│ └── src/
│ └── lib_json/ # JsonCpp 核心源码
│ ├── json_reader.cpp # 解析实现
│ ├── json_value.cpp # 数据结构实现
│ ├── json_writer.cpp # 生成实现
│ ├── config.h.in # 配置文件模板(关键!)
│ └── assertions.h # 内部断言头文件
├── src/ # 你的项目源码
│ └── main.cpp
└── CMakeLists.txt # 项目CMake配置
步骤 2:CMake 配置(核心!)
在项目根目录的 CMakeLists.txt
中添加 JsonCpp 的编译配置,重点解决 config.h
生成 和 头文件 / 源码路径关联:
# -------------------------- 1. 基础配置:指定C++标准 --------------------------
cmake_minimum_required(VERSION 3.10)
project(JsonCppDemo)
set(CMAKE_CXX_STANDARD 11) # JsonCpp 1.9.x 支持 C++11+
set(CMAKE_CXX_STANDARD_REQUIRED ON)# -------------------------- 2. 配置 JsonCpp 路径 --------------------------
# 设定 JsonCpp 源码根目录(根据你的实际路径调整)
set(JSONCPP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/third_party/Json)
# JsonCpp 头文件目录(include/json)
set(JSONCPP_INCLUDE_DIR ${JSONCPP_ROOT}/include)
# JsonCpp 核心源码文件(src/lib_json下的.cpp)
set(JSONCPP_SOURCES${JSONCPP_ROOT}/src/lib_json/json_reader.cpp${JSONCPP_ROOT}/src/lib_json/json_value.cpp${JSONCPP_ROOT}/src/lib_json/json_writer.cpp
)# -------------------------- 3. 生成 JsonCpp 关键配置文件 config.h --------------------------
# JsonCpp 的 config.h 由 config.h.in 模板生成(替换 @XXX@ 宏,如版本、平台)
set(JSONCPP_CONFIG_IN ${JSONCPP_ROOT}/src/lib_json/config.h.in) # 模板路径
set(JSONCPP_CONFIG_OUT ${CMAKE_CURRENT_BINARY_DIR}/jsoncpp_config.h) # 生成路径(放build目录)
configure_file(${JSONCPP_CONFIG_IN}${JSONCPP_CONFIG_OUT}@ONLY # 仅替换 @XXX@ 格式的宏,避免冲突
)# -------------------------- 4. 关联头文件目录 --------------------------
# ① 添加 JsonCpp 公开头文件目录(include/json)
include_directories(${JSONCPP_INCLUDE_DIR})
# ② 添加生成的 config.h 目录(build目录,解决 "config.h 找不到" 问题)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
# ③ 添加 JsonCpp 内部头文件目录(src/lib_json,解决 "assertions.h 找不到" 问题)
include_directories(${JSONCPP_ROOT}/src/lib_json)# -------------------------- 5. 编译项目:关联源码和 JsonCpp --------------------------
# 你的项目源码(如 main.cpp)
add_executable(JsonCppDemosrc/main.cpp${JSONCPP_SOURCES} # 加入 JsonCpp 核心源码
)
步骤 3:修正 JsonCpp 内部头文件引用(关键!)
JsonCpp 源码中默认包含 #include "config.h"
,但我们生成的配置文件是 jsoncpp_config.h
(避免与其他库的 config.h
冲突),需手动修改源码中的引用:
1.打开 third_party/Json/src/lib_json/json_tool.h
,将第 10 行(或包含 config.h
的行):
#include "config.h"
替换为:
#include "jsoncpp_config.h"
2.若其他文件(如 json_reader.cpp
)也包含 config.h
,同样替换为 jsoncpp_config.h
。
3.核心组件与接口
JsonCpp 的核心功能围绕 3 个关键类展开,以及新旧两套接口(推荐使用新接口):
1.核心数据类型:Json::Value
Json::Value
是 JsonCpp 中最基础的类,用于存储任意 JSON 数据(类似 “万能容器”),支持所有 JSON 类型:
- 基础类型:
null
、bool
、int
、double
、std::string
。 - 复合类型:
array
(数组,类似std::vector
)、object
(对象,类似std::map
)。
常用方法:
// 创建不同类型的Value
Json::Value null_val; // 默认是null
Json::Value bool_val(true); // 布尔值
Json::Value int_val(123); // 整数
Json::Value str_val("hello"); // 字符串
Json::Value arr_val; arr_val.append(456); // 数组(添加元素)
Json::Value obj_val; obj_val["key"] = "val"; // 对象(键值对)// 类型判断
bool is_null = null_val.isNull();
bool is_obj = obj_val.isObject();
bool is_arr = arr_val.isArray();// 类型转换(需确保类型匹配,否则返回默认值)
int num = int_val.asInt(); // 转为int
std::string str = str_val.asString(); // 转为string
2.解析 JSON:Json::CharReader
(新接口,推荐)
用于将 JSON 字符串或文件解析为 Json::Value
对象,替代旧版 Json::Reader
(已废弃)。需配合 Json::CharReaderBuilder
使用。
解析流程:
- 创建
CharReaderBuilder
(配置解析选项,如是否允许注释)。 - 获取
CharReader
实例(解析器)。 - 调用
parse()
方法解析 JSON 字符串 / 文件,结果存入Json::Value
。 - 检查解析错误(通过输出参数获取错误信息)。
3.生成 JSON:Json::StreamWriter
(新接口,推荐)
用于将 Json::Value
对象转换为 JSON 字符串,替代旧版 Json::Writer
(已废弃)。需配合 Json::StreamWriterBuilder
使用,支持自定义格式化(缩进、换行等)。
4.基本使用示例
示例 1:解析 JSON 字符串并读取数据
#include <iostream>
#include <string>
#include "json/json.h"int main() {// 待解析的JSON字符串std::string json_str = R"({"name": "JsonCpp","version": 1.9,"is_stable": true,"features": ["parse", "generate", "modify"],"author": {"name": "open-source","email": "none@example.com"}})";// 1. 配置解析器Json::CharReaderBuilder builder;Json::CharReader* reader = builder.newCharReader();// 2. 解析JSON字符串Json::Value root;std::string errors; // 存储解析错误信息bool parse_success = reader->parse(json_str.data(), json_str.data() + json_str.size(), &root, &errors);delete reader; // 释放解析器// 3. 检查解析结果if (!parse_success) {std::cerr << "解析失败:" << errors << std::endl;return 1;}// 4. 读取JSON数据(需确保键存在且类型匹配)std::string name = root["name"].asString(); // "JsonCpp"double version = root["version"].asDouble(); // 1.9bool is_stable = root["is_stable"].asBool(); // truestd::string feature0 = root["features"][0].asString(); // "parse"std::string author_name = root["author"]["name"].asString(); // "open-source"// 输出结果std::cout << "名称:" << name << "\n"<< "版本:" << version << "\n"<< "是否稳定:" << std::boolalpha << is_stable << "\n"<< "第一个特性:" << feature0 << "\n"<< "作者:" << author_name << std::endl;return 0;
}
示例 2:构建 JSON 数据并生成字符串
#include <iostream>
#include <string>
#include "json/json.h"int main() {// 1. 构建JSON数据Json::Value root;// 添加基本类型root["status"] = "success";root["code"] = 200;root["data"]["id"] = 1001;root["data"]["name"] = "test";root["data"]["scores"] = Json::Value(Json::arrayValue); // 初始化数组root["data"]["scores"].append(90.5);root["data"]["scores"].append(88);root["data"]["is_passed"] = true;// 2. 配置生成器(自定义格式化)Json::StreamWriterBuilder builder;builder["indentation"] = " "; // 缩进为2个空格(默认4个)std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());// 3. 生成JSON字符串(写入到字符串流)std::stringstream ss;writer->write(root, &ss);std::string json_str = ss.str();// 输出结果std::cout << "生成的JSON:\n" << json_str << std::endl;return 0;
}
输出结果(格式化后的 JSON):
{"code": 200,"data": {"id": 1001,"is_passed": true,"name": "test","scores": [90.5,88]},"status": "success"
}
示例 3:修改与删除 JSON 数据
#include <iostream>
#include "json/json.h"int main() {// 初始化一个JSON对象Json::Value obj;obj["a"] = 1;obj["b"] = "original";obj["c"] = Json::Value(Json::arrayValue);obj["c"].append(10);obj["c"].append(20);// 1. 修改数据obj["a"] = 2; // 修改已有键的值obj["b"] = "modified";obj["c"][0] = 100; // 修改数组元素// 2. 添加新键值对obj["d"] = false;// 3. 删除键(使用removeMember)obj.removeMember("a");// 输出修改后的结果Json::StreamWriterBuilder builder;std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());writer->write(obj, &std::cout);// 输出:{"b":"modified","c":[100,20],"d":false}return 0;
}
5.高级用法
1.解析含注释的 JSON(非标准扩展)
默认情况下,JSON 标准不支持注释,但 JsonCpp 可通过配置允许解析 //
或 /* */
注释:
Json::CharReaderBuilder builder;
// 允许注释(需包含json/features.h)
builder.settings_["allowComments"] = true;
// 允许单引号(非标准,可选)
builder.settings_["allowSingleQuotes"] = true;
2.处理大型 JSON 文件(避免内存占用过高)
对于大型 JSON 文件,可通过流式解析(逐行读取)减少内存占用:
std::ifstream ifs("large.json");
Json::CharReaderBuilder builder;
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
Json::Value root;
std::string errors;// 从文件流解析(而非一次性读入字符串)
bool success = reader->parse(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>(), &root, &errors
);
3.自定义 JSON 生成格式
通过 StreamWriterBuilder
的配置项自定义输出格式:
Json::StreamWriterBuilder builder;
builder["indentation"] = "\t"; // 用制表符缩进
builder["enableYAMLCompatibility"] = true; // 兼容YAML格式(无尾逗号)
builder["precision"] = 6; // 浮点数精度(保留6位小数)
6.注意事项
1.类型安全:Json::Value
的 asInt()
、asString()
等方法在类型不匹配时会返回默认值(如 0
、空字符串),建议先通过 isInt()
、isString()
等方法检查类型。
2.键存在性:访问 root["key"]
时,若键不存在会返回 null
,建议用 root.isMember("key")
检查键是否存在。
3.线程安全:Json::Value
及解析 / 生成器均不保证线程安全,多线程操作需加锁(如 std::mutex
)。
4.版本兼容性:旧接口(Json::Reader
、Json::StyledWriter
)已被标记为废弃,新项目建议使用 CharReaderBuilder
和 StreamWriterBuilder
。
5.内存管理:Json::Value
内部管理内存,赋值时会自动拷贝数据(大对象拷贝成本高,可考虑移动语义 std::move
)。
6.出现:config.h: No such file or directory,那是因为
未生成 config.h
(源码嵌入方式),或生成路径未加入包含目录。参考2.2,通过 configure_file
生成 jsoncpp_config.h
,并添加 include_directories(${CMAKE_CURRENT_BINARY_DIR})
。
7.总结
JsonCpp 是 C++ 中处理 JSON 的成熟方案,通过 Json::Value
存储数据,CharReader
解析,StreamWriter
生成,接口直观且功能全面。适合各类场景(配置文件解析、API 数据交互、日志格式化等),掌握其核心类和基本流程后,可轻松应对复杂 JSON 操作。