数据织网者:Jsoncpp库深度解析——从C++原生JSON处理到工程级数据交互实战全攻略

文章目录

本篇摘要

本文详解C++生态经典库Jsoncpp的核心用法,涵盖环境搭建、新版API解析/生成功能(如CharReader/StreamWriterBuilder)、类型安全操作及文件交互,来帮助读者快速上手jsoncpp。


前言:

JSON(JavaScript Object Notation)是现代软件开发中最常用的轻量级数据交换格式之一,而 Jsoncpp 是 C++ 生态中最经典、最稳定的 JSON 处理库。无论你是开发配置文件解析、API 数据交互,还是游戏存档管理,掌握 Jsoncpp 都能让你高效处理 JSON 数据。


一、Jsoncpp 是什么?

Jsoncpp 是一个开源的 C++ 库,专门用于解析、生成和操作 JSON 数据。它的特点是:

  • 纯 C++ 实现无需依赖第三方运行时环境
  • API 设计简洁,符合 C++ 开发者的使用习惯。
  • 跨平台支持(Windows/Linux/macOS),兼容主流编译器(GCC/Clang/MSVC)。
  • 稳定性高,被广泛应用于游戏开发(如 Unreal Engine 插件)、嵌入式系统和后端服务。

二、环境准备:如何安装 Jsoncpp?

  1. 获取源码

    访问 Jsoncpp 的官方 GitHub 仓库(https://github.com/open-source-parsers/jsoncpp(点击即跳转)),下载最新版本的源码压缩包(如 jsoncpp-master.zip),解压到本地目录。

  2. 编译为静态库(以 Windows + Visual Studio 为例):

    • 打开解压后的文件夹,进入 jsoncpp-master\makefiles\vs71(根据你的 VS 版本选择,如 vs2022)。
    • 用 Visual Studio 打开 jsoncpp.sln 工程文件。
    • 在解决方案配置中选择 Release 模式,编译 lib_json 项目(生成静态库文件,如 jsoncpp.lib)。
    • 编译完成后,头文件在 include/json 目录,库文件在 libs 目录。
  3. 配置你的项目

    • include/json 目录添加到项目的 头文件搜索路径 (如 Visual Studio 中的 附加包含目录)。
    • 将编译生成的 jsoncpp.lib 添加到项目的 库文件搜索路径 (如 附加库目录 ),并在 链接器输入 中添加 jsoncpp.lib

其他平台Linux/macOS 用户可通过包管理器直接安装(如 sudo apt-get install libjsoncpp-dev))。


三、Jsoncpp 的核心功能与代码示例

Jsoncpp 的核心是三个类:

  • Json::Value:表示 JSON 数据的通用容器(可以是对象、数组、字符串、数字等)。
  • Json::Reader (旧版)/Json::CharReader (新版):解析 JSON 字符串为 Json::Value 对象。
  • Json::StyledWriter (旧版)/Json::StreamWriterBuilder (新版):将 Json::Value 对象转换为格式化的 JSON 字符串。

注意: Jsoncpp 1.9.0 及以上版本推荐使用 CharReaderStreamWriterBuilder(更现代且线程安全),以下示例基于新版 API。


简单使用:

测试效果:

  • 这里可以看到转化成json串的形式就是一层套一层(通过花括号),如果是有数组也就是通过中括号规划出来,其次就是默认存储的时候以十六进制形式存储,因此传输起来也是比较方便的。

对应测试源码:

cpp 复制代码
#include <json/json.h>
#include <iostream>
#include <sstream>
#include <memory>

bool Serialize(Json::Value &jn, std::string &res_str)
{
  Json::StreamWriterBuilder swb;
  std::unique_ptr<Json::StreamWriter> psw(swb.newStreamWriter());

  std::stringstream ss;
  int ret = psw->write(jn, &ss);
  if (ret != 0)
  {
    std::cout << "Json反序列化失败!\n";
    return false;
  }
  res_str = ss.str();
  return true;
}

bool UnSerialize(std::string &res_str, Json::Value &jn)
{
  Json::CharReaderBuilder crb;
  std::shared_ptr<Json::CharReader> cr(crb.newCharReader());
  std::string errs;
  int ret = cr->parse(res_str.c_str(), res_str.c_str() + res_str.size(), &jn, &errs);
  if (ret == false)
  {
    std::cout << "json反序列化失败: " << errs << std::endl;
    return false;
  }
  return true;
}

int main()
{

  char name[] = "张三";
  int age = 18;
  float score[3] = {88, 89.5, 99};

  Json::Value stu;

  stu["姓名"] = name;
  stu["年龄"] = age;
  stu["成绩"].append(score[0]);
  stu["成绩"].append(score[1]);
  stu["成绩"].append(score[2]);
  std::string res;

  bool ret1 = Serialize(stu, res);
  if (ret1 == false)
    return -1;
  std::cout << res << std::endl;

  Json::Value uts;

  bool ret2 = UnSerialize(res, uts);
  if (ret2 == false)
    return -1;

  std::cout << uts["姓名"].asString() << std::endl;
  std::cout << uts["年龄"].asInt() << std::endl;
  int sz = uts["成绩"].size();
  for (int i = 0; i < sz; i++)
  {
    std::cout << uts["成绩"][i].asFloat() << std::endl;
  }
  return 0;
}

解释下:

  • 首先是构建对应json对象,也就是定义Json::Value 对象,然后这里是可以支持嵌套的,也就是可以把这个对象当成对象map来用即可,也就是key-value结构,对应的value可以是数组也就是必须通过append来添加对应成员,value也可以是json对象,类似循环嵌套接口,因此可以把对应描述事物的逻辑结构转化成这种嵌套逻辑模式,最后按照格式转化成json对象在最后变成json串即可。
  • StreamWriterBuilder,创建StreamWriter对象调用write接口来完成对应的把json对象写成对应json串(通过stringstream流)。
  • CharReaderBuilder,创建对应的CharReader来调用对应的parse接口把对应json串解析到对应传入的json对象里面。
  • 其次就是以json对象形式访问的对应的成员的时候,如果要拿到里面的值就是直接类似asString把它转化成对应类型进行后续操作即可。

四、常见问题与注意事项

  1. 旧版 vs 新版 API

    • 旧版(如 Json::ReaderJson::StyledWriter)在 1.9.0 之前常用,但新版(Json::CharReaderJson::StreamWriterBuilder)更安全且线程友好,推荐优先使用。
    • 如果使用旧版,需包含 <json/reader.h><json/writer.h>,但新版已统一到 <json/json.h>
  2. 类型安全

    • 访问字段时务必用正确的 asXXX() 方法(如 asString()asInt()),否则可能导致运行时错误。
    • 如果字段可能不存在,先用 root.isMember("字段名") 检查是否存在,或用 root.get("字段名", 默认值) 提供默认值(如 root.get("age", 0).asInt())。
  3. 文件读写

    • 实际项目中常需要从文件加载 JSON 或保存 JSON 到文件。可以使用 std::ifstream 读取文件内容到字符串,再用上述解析方法;写入时则将生成的 JSON 字符串通过 std::ofstream 保存到文件。

    如(从文件读取 JSON)

    cpp 复制代码
    #include <fstream>
    std::ifstream file("config.json");
    std::string jsonStr((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
    // 然后用 Json::parseFromStream 解析 jsonStr

五、Jsoncpp核心接口总结

核心类/模块总结

类/模块 用途 头文件
Json::Value JSON 数据的万能容器(对象/数组/字符串/数字等) <json/json.h>
Json::CharReaderBuilder 解析 JSON 字符串 的配置器(新版推荐,线程安全) <json/json.h>
Json::CharReader 实际执行解析的底层类(通常通过 CharReaderBuilder 间接使用) <json/json.h>
Json::StreamWriterBuilder 生成 JSON 字符串 的配置器(新版推荐,线程安全) <json/json.h>
Json::StreamWriter 实际执行生成的底层类(通常通过 StreamWriterBuilder 间接使用) <json/json.h>

常用接口功能总结

功能分类 接口/类 所属模块 接口原型/关键方法 用途说明 典型使用场景 一行代码示例
1. 解析 JSON 字符串 Json::CharReaderBuilder 解析模块 Json::CharReaderBuilder builder; 创建 JSON 解析器的配置对象(线程安全) 解析 JSON 字符串前必须初始化 Json::CharReaderBuilder builder;
Json::parseFromStream 解析模块 bool Json::parseFromStream(<br> const Json::CharReaderBuilder& builder,<br> const char* begin, const char* end,<br> Json::Value* root,<br> std::string* errs<br>); 将 JSON 字符串(beginend)解析为 Json::Value 对象,错误信息存到 errs 从文件/网络读取的 JSON 字符串转 C++ 对象 Json::parseFromStream(builder, jsonStr.data(), jsonStr.data()+jsonStr.size(), &root, &errs);
Json::CharReader 解析模块(底层) 通常不直接使用(通过 CharReaderBuilder 调用) 实际执行解析的底层类 底层扩展或特殊需求(新手一般不用) -
2. 生成 JSON 字符串 Json::StreamWriterBuilder 生成模块 Json::StreamWriterBuilder builder; 创建 JSON 生成器的配置对象(线程安全) 生成 JSON 字符串前必须初始化 Json::StreamWriterBuilder builder;
Json::writeString 生成模块 std::string Json::writeString(<br> const Json::StreamWriterBuilder& builder,<br> const Json::Value& root<br>); Json::Value 对象转换为格式化的 JSON 字符串(可读性好) 将 C++ 数据结构保存为 JSON 文件/网络传输 std::string jsonStr = Json::writeString(builder, root);
Json::StreamWriter 生成模块(底层) 通常不直接使用(通过 StreamWriterBuilder 调用) 实际执行生成的底层类 底层扩展或特殊需求(新手一般不用) -
3. 操作 Json::Value(解析后的数据) rootconst std::string& key 通过键名访问 JSON 对象的字段(返回 Json::Value 取对象中的字符串、数字等字段值 std::string name = root["name"].asString();
root["字段名"].asString() Json::Value std::string Json::Value::asString() const 将字段值转为 C++ 字符串 取 JSON 中的文本字段(如 "name": "Alice" std::string name = root["name"].asString();
root["字段名"].asInt() Json::Value int Json::Value::asInt() const 将字段值转为 C++ 整数 取 JSON 中的整数字段(如 "age": 25 int age = root["age"].asInt();
root["字段名"].asBool() Json::Value bool Json::Value::asBool() const 将字段值转为 C++ 布尔值 取 JSON 中的布尔字段(如 "isValid": true bool valid = root["isValid"].asBool();
root["字段名"].asDouble() Json::Value double Json::Value::asDouble() const 将字段值转为 C++ 浮点数 取 JSON 中的浮点数字段(如 "price": 9.9 double price = root["price"].asDouble();
root.isMember("字段名") Json::Value bool Json::Value::isMember(const std::string& key) const 检查 JSON 对象是否包含某个字段 避免访问不存在的字段导致错误 if (root.isMember("name")) { ... }
root.isArray() Json::Value bool Json::Value::isArray() const 判断字段是否为 JSON 数组 安全遍历数组元素 if (root["skills"].isArray()) { ... }
root.isObject() Json::Value bool Json::Value::isObject() const 判断字段是否为 JSON 对象 安全访问嵌套对象 if (root["address"].isObject()) { ... }
rootsize_t index 通过索引访问 JSON 数组的元素 取数组中的某个值(如第 0 个元素) std::string skill = root["skills"][0].asString();
root["数组字段"].size() Json::Value size_t Json::Value::size() const 获取 JSON 数组的长度 遍历数组时获取元素数量 for (size_t i=0; i<root["skills"].size(); i++) { ... }
rootconst std::string& key 访问嵌套 JSON 对象的字段(多层对象) 取嵌套结构中的字段(如 "address.city" std::string city = root["address"]["city"].asString();
4. 配置生成/解析格式 builder["indentation"] = " " StreamWriterBuilder / CharReaderBuilder builder["indentation"] = " "(设置缩进字符串) 控制生成的 JSON 字符串格式(缩进美化) 让生成的 JSON 可读性高(调试用) builder["indentation"] = " ";
builder["indentation"] = "" StreamWriterBuilder / CharReaderBuilder builder["indentation"] = ""(空字符串无缩进) 控制生成的 JSON 字符串格式(紧凑无缩进) 生成紧凑 JSON(节省空间/网络传输) builder["indentation"] = "";

本篇小结

本篇详细接受jsoncpp如何安装,如何使用,以及简单例子介绍常见接口,还有就是最后常见的重要结构,来帮助读者快速上手jsoncpp书写。

相关推荐
果果燕4 小时前
实习笔记(七)GFP自动化插拔测试功能协议解析
c++
宁渡AI大模型4 小时前
河南宁渡科技有限公司|宁渡课堂 AI 全栈面试分享,AI 应用开发高频考点汇总
java·c++·人工智能·python·深度学习·神经网络·rag
代码什么用4 小时前
JSON一文速通
java·json
GG-_-Bond4 小时前
9.1 kv存储内存池模拟面试问题
c++·c
AI吃大瓜4 小时前
人脸检测和行人检测3:C/C++实现YOLOv8 YOLO11 YOLO26人脸检测和人体检测(含源码,可实时检测)
c++·yolov8·人脸检测·人体检测·yolo11·yolo26
Persistent的粽子!5 小时前
C++的内存管理
c++·经验分享·笔记
hetao17338375 小时前
2026-09-13 hetao1733837 的刷题记录
c++·算法
hansang_IR5 小时前
【题解】[JSOI2016] 扭动的回文串
c++·算法
有点。5 小时前
C++03阶段练习(一)
数据结构·c++