跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++

C++ JsonCpp 库基础与核心 API 使用指南

C++ JsonCpp 库是处理 JSON 数据的核心工具,支持解析、生成及修改操作。 JSON 基础规范、JsonCpp 安装配置、核心 API 如 Json::Value 类型判断与转换、序列化与反序列化方法。通过代码示例展示了对象、数组及嵌套结构的操作流程,并总结了常见坑点如 operator[] 副作用、线程安全及编码问题,最后对比了其他 C++ JSON 库特性,为开发者提供完整的使用参考。

晚风叙旧发布于 2026/3/20更新于 2026/9/887 浏览
C++ JsonCpp 库基础与核心 API 使用指南

一、JSON 基础

在学习 JsonCpp 之前,我们先搞懂 JSON 的核心规范,这是后续的基础。

1.1 JSON 核心结构

JSON 仅包含两种核心结构,所有复杂数据均由二者嵌套组合而成:

  • 对象:无序的键值对集合,使用大括号 {} 包裹,是 JSON 的核心复合类型
  • 数组:有序的值集合,使用方括号 [] 包裹,用于存储同类型 / 多类型的有序数据
  • 值:JSON 的最小单元,支持 6 种合法类型:字符串、数字、布尔值(true/false)、null、对象、数组

1.2 强制语法规则

JSON 的语法规范很严格,不符合规则的字符串会直接解析失败,规则如下:

  • 所有键名必须是双引号包裹的 UTF-8 字符串,禁止单引号、无引号
  • 键与值之间必须用英文冒号 : 分隔,多个键值对 / 数组元素用英文逗号 , 分隔
  • 禁止末尾逗号(trailing comma),即最后一个键值对 / 数组元素后不能加逗号
  • 字符串必须使用双引号包裹,支持转义字符(如\n、\t、\"
  • 数字支持整数、浮点数、科学计数法,无单双引号包裹
  • 布尔值仅支持小写的 true/false,空值仅支持小写的 null

1.3 标准 JSON 示例

这里给出一份符合规范的完整 JSON 示例,覆盖所有核心类型:

{
 "name": "John Doe",
 "age": 30,
 "is_student": false,
 "weight": 75.5,
 "skills": [ "JavaScript", "Python", "C++" ],
 "address"        
  

:
{
"street"
:
"123 Main St"
,
"city"
:
"Anytown"
,
"state"
:
"CA"
}
,
"education"
:
null
}

1.4 JSON 核心应用场景

  • 数据交换:HTTP / 微服务 API 的标准数据传输格式,前后端、服务间通信的核心载体
  • 配置文件:应用程序的配置管理,替代 ini、xml 等老旧格式,可读性与扩展性更强
  • 数据存储:轻量级数据持久化,用于日志、用户配置、小型数据集的文件存储
  • 数据序列化:跨语言、跨平台的数据序列化方案,兼容几乎所有主流编程语言

二、JsonCpp 库

JsonCpp 是一个专为 C++ 设计的高性能 JSON 处理库,完全兼容 JSON 标准规范,提供了 JSON 解析、生成、修改、遍历的全能力支持,是 C++ 生态中最成熟的 JSON 库之一。

2.1 核心特性优势

  • 简单易用:提供直观的类 C++ 容器 API,学习成本极低,新手可快速上手
  • 高性能:优化的解析与生成逻辑,可高效处理大批量 JSON 数据
  • 全平台兼容:原生支持 Windows、Linux、macOS、嵌入式等几乎所有操作系统
  • 无额外依赖:不依赖任何第三方库,可无缝集成到任何 C++ 项目中
  • 标准兼容:完全支持 JSON 官方标准,同时提供注释、宽松解析等扩展能力
  • 现代 C++ 支持:完美适配 C++11 及以上标准,支持智能指针、移动语义等现代特性

2.2 常见平台安装方法

2.2.1 Linux 系统(Debian/Ubuntu 系列)

官方 apt 源直接安装:

sudo apt update && sudo apt install libjsoncpp-dev

CentOS/RHEL 系列使用 yum 安装:

sudo yum install jsoncpp-devel
2.2.2 macOS 系统

通过 Homebrew 一键安装:

brew install jsoncpp
2.2.3 Windows 系统

推荐使用 vcpkg 包管理器安装,自动适配 Visual Studio 环境:

vcpkg install jsoncpp:x64-windows
2.2.4 源码编译安装(全平台通用)

适合需要自定义编译选项、适配特殊环境的场景:

  1. 克隆官方源码仓库:https://github.com/open-source-parsers/jsoncpp.git
  2. 进入源码目录,创建编译文件夹:cd jsoncpp && mkdir build && cd build
  3. CMake 生成编译配置:cmake .. -DCMAKE_BUILD_TYPE=Release
  4. 编译与安装:make -j8 && sudo make install

2.3 开发环境基础配置

2.3.1 头文件引入

JsonCpp 的核心头文件有两种常见路径,根据安装方式适配:

  • Debian/Ubuntu apt 安装:#include <jsoncpp/json/json.h>
  • 源码编译、brew、vcpkg 安装:#include <json/json.h>
2.3.2 编译链接

编译时必须链接 jsoncpp 动态库,GCC/Clang 编译参数需添加:

-ljsoncpp

Windows Visual Studio 需在项目属性中添加对应架构的 jsoncpp.lib 作为附加依赖项。

三、JsonCpp 核心 API

JsonCpp 的 API 设计极其清晰,核心分为三大模块:

Json::Value 核心数据类、StreamWriter 序列化模块、CharReader 反序列化模块

3.1 数据类型枚举 ValueType

JsonCpp 用枚举定义了 JSON 支持的所有数据类型,用于类型判断与校验,定义如下:

namespace Json {
 enum ValueType {
  nullValue = 0,      // null 空值
  intValue,           // 有符号整型
  uintValue,          // 无符号整型
  realValue,          // 浮点型 (double)
  stringValue,        // UTF-8 字符串
  booleanValue,       // 布尔值
  arrayValue,         // 数组类型
  objectValue         // 对象类型 (键值对)
 };
}

3.2 核心数据类 Json::Value

Json::Value 是 JsonCpp 的核心,是一个变体类型,可存储任意 JSON 支持的数据类型,模拟了 JSON 的动态类型特性,提供了完整的类型判断、转换、读写能力。

3.2.1 类型判断接口

用于判断 Json::Value 存储的实际数据类型,是类型转换前的必操作,避免类型不匹配抛出异常:

接口方法功能说明
bool isNull() const判断是否为 null 空值
bool isBool() const判断是否为布尔值
bool isInt() const判断是否为 32 位有符号整型
bool isInt64() const判断是否为 64 位有符号整型
bool isUInt() const判断是否为 32 位无符号整型
bool isUInt64() const判断是否为 64 位无符号整型
bool isDouble() const判断是否为浮点型
bool isNumeric() const判断是否为任意数字类型 (整型 / 浮点型)
bool isString() const判断是否为字符串类型
bool isArray() const判断是否为数组类型
bool isObject() const判断是否为对象类型
3.2.2 类型转换接口

将 Json::Value 转换为对应的 C++ 原生类型,仅当类型匹配时可安全调用,否则会抛出 Json::Exception 异常:

接口方法功能说明
const char* asCString() const转换为 C 风格 const char * 字符串,生命周期与原 Value 绑定
std::string asString() const转换为 std::string 字符串
Int asInt() const转换为 32 位有符号整型 int
Int64 asInt64() const转换为 64 位有符号整型 long long
UInt asUInt() const转换为 32 位无符号整型 unsigned int
UInt64 asUInt64() const转换为 64 位无符号整型 unsigned long long
float asFloat() const转换为单精度浮点型 float
double asDouble() const转换为双精度浮点型 double
bool asBool() const转换为布尔值 bool
3.2.3 对象 (键值对) 操作接口

用于操作 JSON 对象的键值对,实现键的增删改查:

接口方法功能说明
Value& operator[](const char* key)通过键名访问对应值,键不存在时自动插入 null 值
Value& operator[](const std::string& key)同上,支持 std::string 类型键名
bool isMember(const std::string& key) const判断对象中是否存在指定键名,无副作用
void removeMember(const std::string& key)删除对象中指定的键值对
std::vector<std::string> getMemberNames() const获取对象中所有键名的列表
3.2.4 数组操作接口

用于操作 JSON 数组,实现元素的增删改查与遍历:

接口方法功能说明
ArrayIndex size() const获取数组元素个数,ArrayIndex 为 unsigned int 别名
bool empty() const判断数组是否为空
void clear()清空数组所有元素
void resize(ArrayIndex newSize)重置数组大小,扩容部分填充 null 值
Value& operator[](ArrayIndex index)通过下标访问数组元素,下标越界时自动扩容
Value& append(const Value& value)向数组末尾追加元素
3.2.5 辅助接口
接口方法功能说明
void swap(Value& other)与另一个 Value 对象交换数据,无内存拷贝,高性能
void copy(const Value& other)深拷贝另一个 Value 对象的所有数据
std::string toStyledString() const快速序列化为带格式化的 JSON 字符串,调试专用

3.3 序列化核心:StreamWriter 系列 API

序列化指的是将 C++ 中的 Json::Value 对象转换为 JSON 格式字符串

核心类为 Json::StreamWriterBuilder(工厂类)与 Json::StreamWriter(序列化执行类)。

核心 API 定义:

namespace Json {
 // 序列化执行类
 class StreamWriter {
 public:
  // 核心方法:将 root 对象序列化,写入输出流 sout
  virtual int write(Value const& root, std::ostream* sout) = 0;
 };
 // 序列化工厂类,用于配置序列化规则、创建 StreamWriter 对象
 class StreamWriterBuilder : public StreamWriter::Factory {
 public:
  // 序列化配置项,可自定义格式化、注释、编码等规则
  Json::Value settings_;
  // 创建 StreamWriter 对象,返回值需用智能指针管理
  StreamWriter* newStreamWriter() const override;
 };
 // 工具函数:直接将 Value 对象序列化为 std::string
 std::string writeString(StreamWriter::Factory const& factory, Value const& root);
}

常用序列化配置项:

配置项取值功能说明
commentStyle"None"/"All"注释输出控制,None 为不输出注释,All 为输出所有注释
indentation字符串缩进字符,默认 " "(两个空格),设为 "" 则生成无缩进的压缩 JSON
emitUTF8true/false是否强制输出 UTF-8 编码,默认 true,建议保持开启
precision数字浮点数序列化的精度,默认 15 位有效数字

3.4 反序列化核心:CharReader 系列 API

反序列化指的是将 JSON 格式字符串解析为 C++ 中的 Json::Value 对象

核心类为 Json::CharReaderBuilder(工厂类)与 Json::CharReader(反序列化执行类)。

核心 API 定义:

namespace Json {
 // 反序列化执行类
 class CharReader {
 public:
  // 核心方法:解析 [beginDoc, endDoc) 区间的 JSON 字符串
  // 解析成功返回 true,结果存入 root;失败返回 false,错误信息存入 errs
  virtual bool parse(
   char const* beginDoc, char const* endDoc,
   Value* root, std::string* errs
  ) = 0;
 };
 // 反序列化工厂类,用于配置解析规则、创建 CharReader 对象
 class CharReaderBuilder : public CharReader::Factory {
 public:
  // 反序列化配置项,可自定义注释支持、宽松解析等规则
  Json::Value settings_;
  // 创建 CharReader 对象,返回值需用智能指针管理
  CharReader* newCharReader() const override;
 };
}

常用反序列化配置项(settings_):

配置项取值功能说明
allowCommentstrue/false是否支持 JSON 中的 // 单行注释与 /* */ 块注释,默认 false
strictRoottrue/false是否严格要求根节点必须是对象或数组,默认 false
allowTrailingCommastrue/false是否允许末尾逗号,默认 false
failIfExtratrue/false解析到多余非空白字符时是否失败,默认 true

四、基本使用方法和示例

(一)基础类型操作

1. 赋值与取值
#include <iostream>
#include <jsoncpp/json/json.h>

int main() {
 // 1. 字符串类型
 Json::Value str_val;
 str_val = "Hello JsonCpp"; // 赋值
 if (str_val.isString()) // 类型判断
 {
  std::cout << "字符串值:" << str_val.asString() << std::endl;
 }

 // 2. 整数类型
 Json::Value int_val;
 int_val = 100;
 if (int_val.isInt())
 {
  std::cout << "整数值:" << int_val.asInt() << std::endl;
 }

 // 3. 浮点类型
 Json::Value double_val;
 double_val = 3.14159;
 if (double_val.isDouble())
 {
  std::cout << "浮点值:" << double_val.asDouble() << std::endl;
 }

 // 4. 布尔类型
 Json::Value bool_val;
 bool_val = true;
 if (bool_val.isBool())
 {
  std::cout << "布尔值:" << std::boolalpha << bool_val.asBool() << std::endl;
 }

 // 5. null 类型
 Json::Value null_val;
 null_val = Json::nullValue; // 显式赋值 null
 if (null_val.isNull())
 {
  std::cout << "null 值:null" << std::endl;
 }
 return 0;
}

输出结果:

字符串值:Hello JsonCpp
整数值:100
浮点值:3.14159
布尔值:true
null 值:null
2. 关键方法说明
方法作用
isString()/asString()判断 / 转换为字符串类型
isInt()/asInt()判断 / 转换为 32 位整数(也支持 isInt64/asInt64)
isDouble()/asDouble()判断 / 转换为浮点类型
isBool()/asBool()判断 / 转换为布尔类型
isNull()判断是否为 null 值(无 asNull () 方法)

(二)JSON 对象(键值对)操作

JSON 对象是无序键值对集合,核心操作是「增 / 删 / 改 / 查」键值对。

1. 完整示例
#include <iostream>
#include <vector>
#include <jsoncpp/json/json.h>

int main() {
 // 1. 创建空 JSON 对象
 Json::Value obj;

 // 2. 新增/修改键值对(key 不存在则新增,存在则覆盖)
 obj["name"] = "张三";
 obj["age"] = 25;
 obj["is_student"] = false;
 obj["score"] = 95.5;

 // 3. 检查键是否存在(避免 operator[] 的副作用)
 if (obj.isMember("name")) // 关键:先判断键存在,再取值
 {
  std::cout << "姓名:" << obj["name"].asString() << std::endl;
 }

 // 4. 获取所有键名(遍历对象)
 std::vector<std::string> keys = obj.getMemberNames();
 std::cout << "\n对象所有键值对:" << std::endl;
 for (const auto& key : keys)
 {
  std::cout << key << " = " << obj[key] << std::endl;
 }

 // 5. 删除键值对
 obj.removeMember("score");
 std::cout << "\n删除 score 后,是否还存在:" << std::boolalpha << obj.isMember("score") << std::endl;

 // 6. 安全取值(带默认值,无副作用)
 std::string city = obj.get("city", "北京").asString();
 std::cout << "城市(默认值):" << city << std::endl;
 return 0;
}

输出结果:

姓名:张三
对象所有键值对:
 name = "张三"
 age = 25
 is_student = false
 score = 95.5
删除 score 后,是否还存在:false
城市(默认值):北京
2. 核心方法说明
方法作用
operator[](const string& key)通过键访问值(无键则自动插入 null)
isMember(const string& key)判断键是否存在(无副作用,必用)
getMemberNames()获取所有键名的 vector 列表
removeMember(const string& key)删除指定键值对
get(key, defaultValue)安全取值(无键则返回默认值,无副作用)

(三)JSON 数组操作

JSON 数组是有序值集合,核心操作是「追加 / 遍历 / 修改 / 清空」。

1. 完整示例
#include <iostream>
#include <jsoncpp/json/json.h>

int main() {
 // 1. 创建空数组
 Json::Value arr;

 // 2. 追加元素(支持不同类型)
 arr.append("C++");
 arr.append("Python");
 arr.append(100);
 arr.append(true);

 // 3. 获取数组长度
 std::cout << "数组长度:" << arr.size() << std::endl;

 // 4. 遍历数组(下标方式)
 std::cout << "\n数组元素:" << std::endl;
 for (int i = 0; i < arr.size(); ++i)
 {
  std::cout << "下标" << i << ":" << arr[i] << std::endl;
 }

 // 5. 修改数组元素
 arr[1] = "Java"; // 覆盖下标 1 的元素
 std::cout << "\n修改后下标 1:" << arr[1].asString() << std::endl;

 // 6. 清空数组
 arr.clear();
 std::cout << "清空后数组长度:" << arr.size() << std::endl;

 // 7. 重置数组大小(扩容/缩容)
 arr.resize(3); // 扩容到 3 个元素,默认填充 null
 std::cout << "扩容后下标 2:" << (arr[2].isNull() ? "null" : "非 null") << std::endl;
 return 0;
}

输出结果:

数组长度:4
数组元素:
 下标 0:"C++"
 下标 1:"Python"
 下标 2:100
 下标 3:true
修改后下标 1:Java
清空后数组长度:0
扩容后下标 2:null
2. 核心方法说明
方法作用
append(const Value&)向数组末尾追加元素
size()获取数组元素个数(返回 ArrayIndex 类型,可转 int)
operator[](int index)通过下标访问元素(越界则自动扩容)
clear()清空数组所有元素
resize(int newSize)重置数组大小(扩容填充 null,缩容截断)
empty()判断数组是否为空(size ()==0)

(四)嵌套结构(对象嵌套对象 / 数组)

实际开发中最常用的场景,核心是「逐层创建 + 逐层访问」。

1. 完整示例
#include <iostream>
#include <jsoncpp/json/json.h>

int main() {
 // 1. 创建嵌套对象(地址)
 Json::Value addr;
 addr["province"] = "广东省";
 addr["city"] = "深圳市";
 addr["street"] = "科技园路";

 // 2. 创建嵌套数组(爱好)
 Json::Value hobbies;
 hobbies.append("编程");
 hobbies.append("阅读");
 hobbies.append("跑步");

 // 3. 根对象嵌套子对象和数组
 Json::Value root;
 root["user"] = "李四";
 root["age"] = 30;
 root["address"] = addr; // 嵌套对象
 root["hobbies"] = hobbies; // 嵌套数组

 // 4. 访问嵌套对象
 if (root.isMember("address") && root["address"].isObject())
 {
  std::cout << "省份:" << root["address"]["province"].asString() << std::endl;
 }

 // 5. 访问嵌套数组
 if (root.isMember("hobbies") && root["hobbies"].isArray())
 {
  std::cout << "\n爱好列表:" << std::endl;
  for (int i = 0; i < root["hobbies"].size(); ++i)
  {
   std::cout << " - " << root["hobbies"][i].asString() << std::endl;
  }
 }

 // 6. 快速输出格式化 JSON(调试用)
 std::cout << "\n完整 JSON 结构:" << std::endl;
 std::cout << root.toStyledString() << std::endl;
 return 0;
}

输出结果:

省份:广东省
爱好列表:
 - 编程
 - 阅读
 - 跑步
完整 JSON 结构:
{
 "address" : {
  "city" : "深圳市",
  "province" : "广东省",
  "street" : "科技园路"
 },
 "age" : 30,
 "hobbies" : [
  "编程",
  "阅读",
  "跑步"
 ],
 "user" : "李四"
}

(五)序列化(Value → JSON 字符串)

步骤构建 Json::Value 数据结构;配置 Json::StreamWriterBuilder(可选,默认紧凑输出);生成 JSON 字符串。

#include <json/json.h>
#include <iostream>
#include <sstream>
#include <string>

int main() {
 // 1. 构建 Json::Value
 Json::Value root;
 root["name"] = "张三";
 root["age"] = 25;
 root["is_student"] = false;

 // 数组
 Json::Value hobbies;
 hobbies.append("篮球");
 hobbies.append("编程");
 root["hobbies"] = hobbies;

 // 嵌套对象
 Json::Value address;
 address["city"] = "北京";
 root["address"] = address;

 // 2. 配置序列化(格式化输出,4 空格缩进)
 Json::StreamWriterBuilder writerBuilder; // 创建 JSON 序列化配置构建器
 writerBuilder["indentation"] = "    "; // Json::StreamWriter:实际执行序列化写入的抽象基类,只能通过 Builder 的 newStreamWriter() 方法创建,禁止直接 new 实例

 // std::unique_ptr:C++ 智能指针,自动管理写入器实例的生命周期
 // newStreamWriter():const 方法,会基于当前 Builder 的配置生成一个独立的写入器实例;同一个 Builder 可重复创建多个 Writer,线程安全
 std::unique_ptr<Json::StreamWriter> writer(writerBuilder.newStreamWriter());

 // 3. 生成 JSON 字符串
 // 核心作用:将 Json::Value 数据写入输出流,最终转换为标准 std::string 字符串
 // 3.1 创建字符串输出流,作为序列化的输出载体
 // std::ostringstream 是 C++ 标准库的字符串输出流,专门用于内存中的字符串拼接
 // Json::StreamWriter 的 write 方法要求传入 std::ostream* 类型的输出流,用 ostringstream 可以安全、便捷地将流内容转为 std::string
 // 相比直接操作 char 数组,无内存溢出风险,同时支持流式增量写入,适配大体积 JSON 场景
 std::ostringstream oss;

 // 3.2 执行序列化核心操作:将 Json::Value 写入输出流
 // 函数原型:virtual int write(const Value& root, std::ostream* sout) = 0;
 // - 第一个参数 root:待序列化的根 Json::Value 对象,支持任意合法 JSON 结构(对象、数组、基本类型),const 修饰保证序列化不会修改原数据
 // - 第二个参数 &oss:输出流的指针,序列化生成的 JSON 内容会完整写入这个流中
 // - 返回值 int:序列化执行结果,0 表示序列化成功,非 0 表示序列化失败(流写入失败、不支持的特殊类型等)
 // 【生产环境最佳实践】必须判断返回值,避免序列化静默失败导致空字符串/不完整 JSON
 writer->write(root, &oss);

 // 3.3 将输出流中的内容,转换为最终的 JSON 字符串
 // oss.str() 会提取 std::ostringstream 中存储的完整内容,返回标准 std::string,就是我们最终需要的格式化 JSON 字符串
 // 后续可直接用于控制台输出、写入文件、网络传输等场景
 std::string jsonStr = oss.str();
 std::cout << "序列化结果:\n" << jsonStr << std::endl;
 return 0;
}

除了 indentation,你还可以通过 writerBuilder 添加这些常用配置:

列举常见的序列化方式:

方式 1:便捷函数 writeString(推荐日常使用)

核心特点一行代码完成序列化,是 StreamWriter 的高级封装 可配置缩进(紧凑 / 格式化输出) 直接返回 std::string,无需手动操作流

适用场景绝大多数日常场景(接口请求、数据存储) 需要灵活配置缩进格式的场景 单次 / 少量序列化操作(无需复用写入器)

方式 2:手动创建 StreamWriter(灵活输出控制)

核心特点底层用法,手动管理 StreamWriter 生命周期 可复用写入器(多次序列化更高效) 支持输出到任意 std::ostream(控制台、文件、网络流)

适用场景多次序列化(循环中复用写入器,减少创建开销) 需要输出到文件 / 网络流等非字符串目标 需精细控制输出过程的场景

方式 3:toStyledString(极简调试用)

核心特点零配置,一行代码完成固定格式化输出(带缩进 / 换行,不可修改) 底层封装了默认的 StreamWriter

适用场景开发调试、日志打印 临时查看 JSON 结构(无需配置格式) 不推荐生产环境(固定格式,无法紧凑输出)

方式 4:自定义 StreamWriter(高级定制)

核心特点继承 Json::StreamWriter 重写序列化逻辑 支持特殊规则(如自定义布尔值、日期格式) 极致灵活,但开发成本高

适用场景需要自定义序列化规则(如特殊字符转义、非标格式) 对接特殊第三方接口(要求非标准 JSON 格式) 非必要不使用(增加维护成本)

(六)反序列化(JSON 字符串 → Value)

步骤配置 Json::CharReaderBuilder(可选,默认宽松解析);调用 parse() 解析字符串到 Json::Value;安全取值(先判断类型,再转换)。

#include <json/json.h>
#include <iostream>
#include <string>

int main() {
 // 待解析的 JSON 字符串
 std::string jsonStr = R"({ "name": "张三", "age": 25, "hobbies": ["篮球", "编程"], "address": {"city": "北京"} })";

 // 1. 配置反序列化
 Json::CharReaderBuilder readerBuilder; // 创建 JSON 反序列化配置构建器
 readerBuilder["rejectDupKeys"] = true; // 拒绝重复键

 // 根据配置创建 JSON 解析器实例
 // Json::CharReader:实际执行 JSON 字符串解析的抽象基类,只能通过 Builder 的 newCharReader() 方法创建,不可直接 new
 // std::unique_ptr:智能指针,自动管理解析器实例的生命周期
 // newCharReader():const 方法,会基于当前 Builder 的配置生成一个独立的解析器实例;同一个 Builder 可重复创建多个 Reader,线程安全
 std::unique_ptr<Json::CharReader> reader(readerBuilder.newCharReader());

 // 2. 解析
 Json::Value root; // 接收解析结果的容器
 std::string errs; // 接收解析错误信息的容器
 bool parseOk = reader->parse(
  jsonStr.c_str(), // 待解析 JSON 字符串的起始内存地址
  jsonStr.c_str() + jsonStr.size(), // 待解析 JSON 字符串的结束内存地址
  &root, &errs
 );

 if (!parseOk)
 {
  std::cerr << "解析失败:" << errs << std::endl;
  return 1;
 }

 // 3. 安全取值
 std::cout << "姓名:" << root.get("name", "未知").asString() << std::endl;
 std::cout << "年龄:" << root.get("age", 0).asInt() << std::endl;

 // 遍历数组
 if (root["hobbies"].isArray())
 {
  std::cout << "爱好:";
  for (const auto& hobby : root["hobbies"])
  {
   std::cout << hobby.asString() << " ";
  }
  std::cout << std::endl;
 }

 // 访问嵌套对象
 if (root["address"].isObject())
 {
  std::cout << "城市:" << root["address"]["city"].asString() << std::endl;
 }
 return 0;
}

解析步骤说明:

几种常见的反序列化的解析方式:

1. parseFromStream(主流)

核心特点:基于 std::istream 设计,支持字符串流、文件流、网络流等任意输入源 可通过 CharReaderBuilder 配置解析规则(如注释支持、精度控制) 线程安全、扩展性强

适用场景:新项目首选(兼容所有 JsonCpp 新版本) 处理大文件 / 流式数据(无需一次性加载全部内容) 需要自定义解析规则的场景

2. fromString(简单)

核心特点:parseFromStream 的封装版,直接接收字符串,无需手动创建流 零配置快速解析,牺牲部分灵活性换取简洁性

适用场景:简单场景(无需配置解析规则) 快速调试、小体积 JSON 字符串解析

3. Json::Reader::parse(旧版 API)

核心特点:早期 JsonCpp 主流方式,现已被标记为「过时」 直接操作字符串指针,C 风格明显 配置选项少,非线程安全

适用场景:维护老旧项目(无法升级 JsonCpp 版本) 临时兼容历史代码(建议逐步替换为新 API)

4. 自定义 CharReader(高级解析)

核心特点:继承 Json::CharReader 重写解析逻辑 支持非标 JSON 格式(如自定义注释、特殊字符) 开发成本高,仅适用于极特殊场景

建议:新项目优先使用 parseFromStream(兼顾灵活性和性能);简单场景可使用 FromString 简化代码;

(七)JSON 文件的读写操作

实际开发中,我们经常需要从 JSON 文件读取配置,或将 JSON 数据写入文件持久化,这里给出完整的文件读写实现。

#include <iostream>
#include <fstream>
#include <memory>
#include <jsoncpp/json/json.h>

// 从文件读取并解析 JSON
bool readJsonFromFile(const std::string& file_path, Json::Value& root) {
 // 打开文件
 std::ifstream ifs(file_path, std::ios::in | std::ios::binary);
 if (!ifs.is_open())
 {
  std::cerr << "文件打开失败:" << file_path << std::endl;
  return false;
 }

 // 读取文件内容到字符串
 std::string json_str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
 ifs.close();

 // 反序列化解析
 Json::CharReaderBuilder crb;
 crb.settings_["allowComments"] = true;
 std::unique_ptr<Json::CharReader> pcr(crb.newCharReader());
 std::string err_msg;
 bool ret = pcr->parse(json_str.data(), json_str.data() + json_str.size(), &root, &err_msg);
 if (!ret)
 {
  std::cerr << "JSON 解析失败:" << err_msg << std::endl;
  return false;
 }
 std::cout << "JSON 文件读取解析成功" << std::endl;
 return true;
}

// 将 Json::Value 序列化并写入文件
bool writeJsonToFile(const std::string& file_path, const Json::Value& root) {
 // 序列化配置
 Json::StreamWriterBuilder swb;
 swb.settings_["indentation"] = "    ";
 swb.settings_["emitUTF8"] = true;
 std::unique_ptr<Json::StreamWriter> psw(swb.newStreamWriter());

 // 打开文件
 std::ofstream ofs(file_path, std::ios::out | std::ios::binary | std::ios::trunc);
 if (!ofs.is_open())
 {
  std::cerr << "文件打开失败:" << file_path << std::endl;
  return false;
 }

 // 序列化并写入文件
 int ret = psw->write(root, &ofs);
 ofs.close();
 if (ret != 0)
 {
  std::cerr << "JSON 序列化写入失败" << std::endl;
  return false;
 }
 std::cout << "JSON 文件写入成功" << std::endl;
 return true;
}

// 测试主函数
int main() {
 // 读取 JSON 文件
 Json::Value config;
 if (!readJsonFromFile("./config.json", config))
 {
  return -1;
 }

 // 修改配置数据
 config["version"] = "1.0.1";
 config["update_time"] = "2024-01-01";
 config["server"]["port"] = 8080;

 // 写入新的 JSON 文件
 if (!writeJsonToFile("./new_config.json", config))
 {
  return -1;
 }
 return 0;
}

五、避坑指南

6.1 坑点与解决方案

坑 1:operator [] 的副作用(最常见)

问题:使用非 const 的 Json::Value 的 operator[] 访问不存在的键时,会自动向对象中插入该键,值为 null,导致原对象被意外修改。

// 错误示例:意外插入了"not_exist_key"键
Json::Value obj;
if (obj["not_exist_key"].isNull())
{
 std::cout << "键不存在" << std::endl;
}
// 此时 obj 中已经存在"not_exist_key"键,值为 null

解决方案:

  • 先通过 isMember() 判断键是否存在,再访问值
  • 使用 const 引用访问,const 版本的 operator[] 不会修改原对象,键不存在时返回静态 null 值
  • 使用 get(const char* key, const Value& defaultValue) 方法,无副作用,支持默认值
坑 2:类型不匹配导致的程序崩溃

问题:未判断类型直接调用 asXXX() 方法,类型不匹配时会直接抛出 Json::Exception 异常,未捕获时会导致程序崩溃。

解决方案:严格遵循「先判断类型,再转换取值」的流程,所有类型转换前必须做类型校验。

坑 3:数组越界自动扩容

问题:使用 operator[] 访问数组下标超过数组长度时,会自动将数组扩容到该下标 + 1 的大小,扩容部分填充 null 值,导致数组意外变大。

解决方案:访问数组前先判断下标是否小于数组 size(),禁止越界访问。

坑 4:带注释的 JSON 解析失败

问题:JSON 字符串中包含 // 或 /* */ 注释时,默认解析会直接失败。

解决方案:显式开启注释支持:crb.settings_["allowComments"] = true;

坑 5:字符串编码乱码

问题:传入 GBK、GB2312 等非 UTF-8 编码的字符串,序列化 / 反序列化后出现乱码。

解决方案:JsonCpp 原生仅支持 UTF-8 编码,所有字符串必须转换为 UTF-8 格式后再传入。

坑 6:线程安全问题

问题:多线程同时读写同一个 Json::Value 对象,出现数据竞争、程序崩溃。

解决方案:Json::Value 不是线程安全的,多线程环境下,读写同一个对象必须加互斥锁保护。

6.2 编码建议

  • const 优先:访问 JSON 数据时,优先使用 const 引用,避免 operator[] 的副作用,同时提升性能
  • 异常捕获:所有 JsonCpp 操作都建议包裹在 try-catch 中,捕获 Json::Exception 异常,避免程序意外崩溃
  • 结构化封装:复杂 JSON 结构封装为 C++ 结构体,提供对应的序列化 / 反序列化方法,提升代码可维护性
  • 内存优化:大数据量 JSON 处理时,使用 swap() 方法避免深拷贝,使用 resize() 预分配数组空间
  • 网络传输优化:序列化网络传输的 JSON 时,关闭缩进(indentation="")生成压缩格式,减少数据体积
  • 调试优化:调试时使用 toStyledString() 快速生成格式化 JSON,定位数据问题

六、JsonCpp 与其他 C++ JSON 库对比

C++ 生态中还有多个优秀的 JSON 库,这里做横向对比

库名称核心特点优势劣势适用场景
JsonCpp经典全功能库,非 header-only兼容性极强,支持老 C++ 标准,稳定成熟,工业级验证性能中等,现代特性支持不如新库老项目维护、需要兼容 C++03、企业级稳定优先的项目
nlohmann/json现代 C++ header-only 库用法极简,STL 兼容,功能丰富,header-only 无需编译编译耗时较长,大数据量性能一般新项目快速开发、追求开发效率、无需极致性能的场景
RapidJSON腾讯开源的极致性能库性能顶尖,内存占用极低,全功能支持API 较复杂,学习成本高,报错不友好高频大数据量 JSON 处理、性能敏感的场景(如游戏、高并发服务)

目录

  1. 一、JSON 基础
  2. 1.1 JSON 核心结构
  3. 1.2 强制语法规则
  4. 1.3 标准 JSON 示例
  5. 1.4 JSON 核心应用场景
  6. 二、JsonCpp 库
  7. 2.1 核心特性优势
  8. 2.2 常见平台安装方法
  9. 2.2.1 Linux 系统(Debian/Ubuntu 系列)
  10. 2.2.2 macOS 系统
  11. 2.2.3 Windows 系统
  12. 2.2.4 源码编译安装(全平台通用)
  13. 2.3 开发环境基础配置
  14. 2.3.1 头文件引入
  15. 2.3.2 编译链接
  16. 三、JsonCpp 核心 API
  17. 3.1 数据类型枚举 ValueType
  18. 3.2 核心数据类 Json::Value
  19. 3.2.1 类型判断接口
  20. 3.2.2 类型转换接口
  21. 3.2.3 对象 (键值对) 操作接口
  22. 3.2.4 数组操作接口
  23. 3.2.5 辅助接口
  24. 3.3 序列化核心:StreamWriter 系列 API
  25. 3.4 反序列化核心:CharReader 系列 API
  26. 四、基本使用方法和示例
  27. (一)基础类型操作
  28. 1. 赋值与取值
  29. 2. 关键方法说明
  30. (二)JSON 对象(键值对)操作
  31. 1. 完整示例
  32. 2. 核心方法说明
  33. (三)JSON 数组操作
  34. 1. 完整示例
  35. 2. 核心方法说明
  36. (四)嵌套结构(对象嵌套对象 / 数组)
  37. 1. 完整示例
  38. (五)序列化(Value → JSON 字符串)
  39. (六)反序列化(JSON 字符串 → Value)
  40. (七)JSON 文件的读写操作
  41. 五、避坑指南
  42. 6.1 坑点与解决方案
  43. 坑 1:operator [] 的副作用(最常见)
  44. 坑 2:类型不匹配导致的程序崩溃
  45. 坑 3:数组越界自动扩容
  46. 坑 4:带注释的 JSON 解析失败
  47. 坑 5:字符串编码乱码
  48. 坑 6:线程安全问题
  49. 6.2 编码建议
  50. 六、JsonCpp 与其他 C++ JSON 库对比

更多推荐文章

查看全部
  • Linux 核心 IO 模型深析:CMake 构建与 Poll 多路转接实现
  • 量子计算驱动 Python 医疗诊断:变分量子分类器实战
  • 宇树机器人 (Go2/B2/H1) 的 ROS 2 Humble 部署笔记
  • 双指针算法初阶详解:移动零与复写零
  • Linux C/C++ 编译参数详解:-I, -l, -L
  • AI 图像生成提示词:新手入门指南与最佳实践
  • Java 微服务电商架构:Spring Cloud 多商户与 O2O 方案解析
  • Spring 中@Autowired 与@Resource 注解的核心区别
  • 网络安全工程师职业发展路径与行业现状分析
  • 基于大模型构建集成 GitHub 的自动化工作流实战指南
  • DeepMind 提出欧几里得 Transformer:2.5 天完成 1 年分子动力学模拟
  • 从零搭建可落地 AI Agent 的全流程实操指南
  • GLM-5 发布:开源模型新标杆,Agentic 能力与训练架构解析
  • 大模型岗位面试总结:24 家公司,9 个 Offer
  • OpenClaw QQ 机器人接入指南
  • Windows11 VMware 17.6.0 更新 Tools 报错无法连接服务器解决方案
  • Lottie-Web 动画开发技术指南
  • C++ 无反射 JSON 序列化:AIGCJson 的宏与模板魔法
  • React 前端模拟内存溢出及 Chrome DevTools 内存泄漏排查
  • SpringBoot 低代码 JSON 表单引擎与审批流实现

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online