nlohmann/json是c++事实标准json库,头文件即用、语法直观,但需注意utf-8校验、异常捕获、大文件流式解析、windows路径编码、at()与[]取值差异及类型安全转换。

用 nlohmann/json 读取 JSON 文件最省心
直接上结论:C++ 没有标准 JSON 解析库,nlohmann/json 是当前事实标准,头文件即用,不用编译安装,对新手和项目快速集成最友好。
它把 JSON 当成类似 std::map 和 std::vector 的容器来用,写法直观。但要注意——它默认不校验编码,UTF-8 非法字节会直接抛 json::parse_error 异常,不是静默跳过。
实操建议:
- 用
#include <nlohmann></nlohmann>,确保头文件路径正确(推荐用 vcpkg 或 conan 管理) - 读文件必须自己打开并传入字符串:
json j = json::parse(file_content),不能直接传std::ifstream - 别漏掉异常捕获:
try { ... } catch (const json::parse_error& e) { ... },否则非法 JSON 会让程序崩溃 - 如果 JSON 很大(>10MB),避免一次性读进
std::string,考虑流式解析(见下一条)
大 JSON 文件别全读进内存,用 json_sax 流式处理
当 JSON 文件超过几 MB,或结构已知(比如只关心 "items" 数组里的 "id" 字段),全量解析浪费内存还慢。这时候该用 SAX 模式——边读边处理,不建完整 DOM 树。
立即学习“C++免费学习笔记(深入)”;
它本质是实现一个回调类,重载 key()、string()、number_integer() 等函数,nlohmann/json 在解析时逐个调用。
实操建议:
- 继承
nlohmann::json_sax_dom_callback_parser或手写最简json_sax接口实现 - 用
json::sax_parse(input_stream, sax_handler)替代json::parse() - 注意:SAX 模式不支持随机访问,也无法回退;字段顺序依赖 JSON 原文,不能假设
"name"一定在"age"前 - 典型坑:在
start_object()里没重置状态变量,导致嵌套对象字段错乱
从 std::filesystem::path 读 JSON 容易忽略路径编码问题
Windows 下用 std::filesystem::path 构造路径再转 std::string,遇到中文路径大概率出错——path.string() 返回的是本地窄编码(如 GBK),而 nlohmann/json::parse() 只认 UTF-8 字符串。
结果就是文件明明存在,却报 [json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal,其实根本没读到内容。
实操建议:
- Windows 上统一用
path.u8string()获取 UTF-8 编码的路径字符串 - Linux/macOS 用
path.string()没问题,但为跨平台一致,也建议统一用u8string() - 读文件内容时,确认
std::ifstream以二进制模式打开:std::ifstream f(path, std::ios::binary),避免换行符被悄悄转换 - 别依赖
std::filesystem::exists()的返回值判断 JSON 是否可读——它只查路径,不校验读权限或编码
解析后取值写错括号类型,operator[] 和 at() 行为完全不同
这是新手最高频的崩溃点:j["user"]["name"] 看似自然,但一旦 "user" 不存在,[] 会自动插入空对象,后续取 "name" 还是空,不报错也不提示;而 j.at("user").at("name") 会在缺失时立刻抛 out_of_range 异常。
更隐蔽的是类型误判:用 j["count"] 当 int 用,但实际是 double(JSON 规范里所有数字都是浮点),强制转型可能丢精度。
实操建议:
- 开发阶段一律用
at(),上线前再权衡是否换[]避免异常开销 - 取数值优先用
j["val"].get<int>()</int>或j["val"].get<long long>()</long>,别用(int)j["val"] - 不确定字段是否存在时,先用
j.contains("field")判断,再安全取值 - 嵌套深的路径(如
j["data"]["list"][0]["meta"]["tags"])建议拆成多步 +at(),方便定位哪一层缺失
JSON 解析本身不难,难的是边界情况:路径编码、内存模型、异常分支、类型隐式转换。这些地方不显式处理,上线后出问题很难复现。










