nlohmann/json 读取本地文件需先用 std::ifstream(二进制模式)读取内容再解析,不可直接传路径;访问嵌套结构须用 contains()、value() 或 at() 避免 out_of_range;反序列化结构体需手动实现 from_json();中文乱码主因是 Windows 控制台编码非 UTF-8。

如何用 nlohmann/json 读取本地 JSON 文件
直接用 nlohmann::json::parse() 无法处理文件路径,必须先读取文件内容为字符串,再解析。常见错误是传入文件名给 parse(),结果抛出 parse_error 异常。
推荐做法:用 std::ifstream 按二进制模式读取(避免 Windows 换行符截断),再用 nlohmann::json::parse() 解析:
std::ifstream f("config.json");
if (!f.is_open()) {
throw std::runtime_error("failed to open config.json");
}
nlohmann::json j = nlohmann::json::parse(f);
- 不要用
std::ifstream::rdbuf()直接构造 string —— 它不保证 null 终止,可能引发解析失败 - 如果 JSON 文件含 BOM(如 UTF-8 with BOM),
parse()默认会报错;需手动跳过前 3 字节或用std::string做预处理 - 调试时可加异常捕获并打印
e.what(),例如:"[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value"
访问嵌套对象和数组的正确写法
nlohmann/json 不支持链式访问如 j["a"]["b"]["c"] 在键不存在时静默返回空值——它会抛出 out_of_range。生产代码必须主动检查层级是否存在。
安全访问方式有三种:
立即学习“C++免费学习笔记(深入)”;
- 用
contains()预检:if (j.contains("user") && j["user"].contains("name")) { std::string name = j["user"]["name"]; } - 用
value()提供默认值:int timeout = j.value("server.timeout", 30);(注意:仅适用于基本类型,不支持对象/数组默认值) - 用
at()+ try/catch 捕获out_of_range,适合必须严格校验的场景
数组访问同理:j["items"][i] 在 i >= j["items"].size() 时崩溃;应先判 j["items"].is_array() 和长度。
从 json 对象反序列化到 C++ 结构体
nlohmann/json 不自动绑定结构体,需手动实现 from_json() 和 to_json() 两个非成员函数。这是最容易漏掉的步骤,否则编译报错 "no matching function for call to 'from_json'"。
示例结构体定义:
struct Config {
std::string host;
int port;
};
void from_json(const nlohmann::json& j, Config& c) {
c.host = j.at("host").get();
c.port = j.at("port").get();
}
-
at()比[]更安全,缺失字段直接抛异常,避免静默错误 - 若字段可选,改用
j.value("port", 8080),但注意value()返回的是临时值,不能用于非基本类型 - 嵌套结构体需为每个子类型单独定义
from_json,且必须在使用前声明(头文件中建议放在结构体定义后立即实现)
中文字符串乱码与编码注意事项
nlohmann/json 内部完全基于 UTF-8,但 Windows 控制台默认是 GBK,导致 std::cout 显示乱码——这不是库的问题,而是输出环境未适配。
- Linux/macOS 一般无问题;Windows 下若用 VS 控制台,需在程序开头加:
SetConsoleOutputCP(CP_UTF8); - 写入文件时,确保用 UTF-8 编码保存(VS 中另存为 → 编码选 “UTF-8 无签名”),否则
parse()会因非法字节失败 - JSON 标准允许 Unicode 转义(
\u4f60),但直接写中文更直观;只要源文件、编译器、运行环境三者 UTF-8 一致,就无需转义
最常被忽略的是文件保存编码和控制台编码不一致,花半天调 parse_error 却没检查记事本另存为用了 ANSI。










