c++如何解析JSON数据_c++ jsoncpp库使用教程【实战】

应使用 Json::CharReaderBuilder 构造解析器并检查 parseFromStream 返回值,错误时通过 errs 获取详细信息,避免直接访问未成功解析的空对象。

怎么用 JsonCpp 读取字符串里的 JSON

JsonCpp 不自带解析器,得手动构造 Json::CharReaderBuilder 或用旧版 Json::Reader。新版推荐前者,更安全、支持 Unicode。

常见错误是直接传 raw string 给 parse() 却忽略返回值,导致解析失败却继续访问空对象:

Json::Value root;
Json::CharReaderBuilder builder;
std::string errs;
std::istringstream ss("{\"name\":\"alice\",\"age\":30}");
if (!Json::parseFromStream(builder, ss, &root, &errs)) {
    // 必须检查!errs 里有具体错误位置和原因
    std::cerr << "JSON parse error: " << errs << std::endl;
    return;
}
  • Json::CharReaderBuilder 默认启用 strictMode,不接受 trailing comma、单引号、注释等非标准写法
  • 如果输入来自网络或文件,注意编码:JsonCpp 只处理 UTF-8,别传 GBK 或 UTF-16
  • 不要用 Json::Reader(已弃用),它在 v1.9+ 中被标记为 deprecated,且线程不安全

如何安全访问嵌套字段并避免崩溃

直接链式调用 root["data"]["items"][0]["id"] 很危险——任一中间层缺失都会返回空 Json::Value,但 asInt()asString() 在空值上调用会抛 std::logic_error

正确做法是逐层检查 isNull()isMember(),或用带默认值的 get()

// 安全写法:提供默认值,类型自动转换
int id = root.get("data", Json::Value::nullRef)
             .get("items", Json::Value::nullRef)
             .get(0, Json::Value::nullRef)
             .get("id", Json::Value(0)).asInt();

// 或更清晰的判断 if (root.isObject() && root.isMember("user") && root["user"].isObject() && root["user"].isMember("email")) { std::string email = root["user"]["email"].asString(); }

  • Json::Value::nullRef 是轻量占位符,比构造新 Json::Value() 更高效
  • get(key, defaultValue)defaultValue 类型必须和期望访问类型兼容,否则可能静默转成 0 或空串
  • 数组索引越界不会报错,array[100] 返回空值,务必先用 array.size() 判断

怎么把 C++ 对象序列化成 JSON 字符串

输出控制权在 Json::StreamWriterBuilder,不是简单调 toString() 就完事。默认格式是紧凑型(无换行缩进),调试时很难看。

Json::StreamWriterBuilder builder;
builder["indentation"] = "  ";  // 注意:必须是字符串,不能是 \t
builder["commentStyle"] = "None"; //

禁用注释(默认可能加 /* ... */) std::string json_str = Json::writeString(builder, root);
  • 如果要兼容老系统或日志友好,设 builder["indentation"] = "" 回到紧凑模式
  • root.toStyledString() 是快捷方式,但无法定制,且内部固定用 4 空格缩进、启用注释,不适合生产环境
  • 浮点数精度默认 17 位,如需控制小数位数,得先转成字符串再塞进 Json::Value,JsonCpp 不提供 setPrecision()

链接和编译时最容易漏掉的细节

JsonCpp 编译后分静态库 jsoncpp 和头文件两部分,CMake 项目常只 link 库却忘了 include 目录,报 Json/json.h: No such file

CMakeLists.txt 正确写法示例:

find_package(jsoncpp REQUIRED)
target_link_libraries(myapp PRIVATE jsoncpp_lib)
target_include_directories(myapp PRIVATE ${jsoncpp_INCLUDE_DIRS})
  • Ubuntu/Debian 上装的是 libjsoncpp-dev,但头文件路径是 /usr/include/jsoncpp/json/json.h,所以 include 时得写 #include ,不是
  • Windows 下若用 vcpkg,包名是 jsoncpp,但生成的库名可能是 jsoncpp.libjsoncpp_static.lib,取决于是否开启 JSONCPP_LIB_BUILD_SHARED
  • Release 模式下,JsonCpp 会关掉部分运行时检查(如类型断言),所以开发期出现的 LogicError 在 Release 可能变成静默错误或崩溃

最常被跳过的一步:没验证输入 JSON 是否合法就直接 parse,结果程序在用户上传的畸形数据上当场退出。解析前加个 std::string::find_first_not_of(" \t\r\n") != std::string::npos 至少能防空输入。