用nlohmann/json读JSON文件最省事,但需用二进制模式打开并手动跳过UTF-8 BOM(EF BB BF),且必须用try-catch捕获parse_error异常。

用 nlohmann/json 读文件最省事,但得防 UTF-8 BOM 和异常
绝大多数配置文件是小到中等体积的 JSON,nlohmann/json 是当前最快上手、代码最干净的选择——它不编译、不链接、头文件一拖就跑。但直接 std::ifstream >> 时容易栽在 Windows 记事本保存的带 BOM 的 UTF-8 文件上:解析会静默失败或抛 nlohmann::json::parse_error。
- 务必用
std::ifstream file("config.json", std::ios::binary)打开,再调file.imbue(std::locale(file.getloc(), new std::codecvt_utf8<wchar_t>))</wchar_t>不现实,更简单的是先跳过 BOM:std::ifstream file("config.json", std::ios::binary); file.seekg(0, std::ios::end); size_t size = file.tellg(); file.seekg(0); std::vector<char> buf(size + 1); file.read(buf.data(), size); if (size >= 3 && buf[0] == '\xEF' && buf[1] == '\xBB' && buf[2] == '\xBF') { // 跳过 BOM json j = json::parse(buf.data() + 3, buf.data() + size); } else { json j = json::parse(buf.data(), buf.data() + size); } - 永远包
try-catch,尤其线上环境:catch (const nlohmann::json::parse_error& e) { std::cerr - 别用
operator[]直接取值,优先用.value("key", default_value)或.at("key")(后者越界抛异常,比静默返回 null 更安全)
读配置常用字段类型怎么安全取值?
配置项不是所有都存在,也不是所有类型都如你所愿。比如 "timeout" 字段可能被误写成字符串 "30",而你的代码期望 int;又或者 "features" 本该是数组,却空着或写成了对象。
-
j.value("timeout", 5000)安全兜底,但注意:如果原始值是字符串"5000",value()不自动转类型,仍返回字符串——得手动.get<int>()</int>,且可能 throw - 推荐组合:
if (j.contains("timeout") && j["timeout"].is_number_integer()) { int t = j["timeout"]; } - 数组字段必须先
is_array()检查,否则j["list"][0]在非数组时返回 null,后续取.get<:string>()</:string>会 crash - 嵌套对象如
j["database"]["host"],建议拆成两步:if (j.contains("database") && j["database"].is_object()) { auto& db = j["database"]; if (db.contains("host")) { ... } }
rapidjson 更快,但配置场景里多数时候没必要
如果你的配置文件超过 1MB,或每秒要加载几百次(比如微服务热重载),rapidjson 的 DOM 解析确实快 3–5 倍,内存也更可控。但它要求你显式检查每个字段类型,API 冗长,出错提示不如 nlohmann 友好。
- 不用
document["key"].GetString()前,必须确认document.HasMember("key") && document["key"].IsString(),漏一个就segmentation fault - 没有类似
.value()的兜底机制,所有默认值得自己写 if 分支 - 对配置这种“人写、人读、偶尔改”的文本,开发效率和可维护性远比几毫秒解析时间重要——除非压测证明它是瓶颈
jsoncpp 适合老项目或需要静态链接的构建环境
如果你的项目已用 CMake + find_package(JsonCpp),或部署环境禁止动态库(如某些嵌入式容器),jsoncpp 仍是稳妥选择。它的 API 虽然啰嗦,但行为稳定、文档全、错误信息明确。
立即学习“C++免费学习笔记(深入)”;
- 新版必须用
Json::CharReaderBuilder,旧版Json::Reader已弃用,但网上大量教程还在教它,容易配错 - 解析后取值必须用
.asString()/.asInt()等方法,不能直接赋值给std::string——否则编译不过 - 写配置时,
Json::StreamWriterBuilder默认不缩进,要美化得手动设:builder["indentation"] = " ";
真正麻烦的从来不是选哪个库,而是配置字段语义模糊、缺少文档、上线后才发现某个字段被悄悄改了类型。所以哪怕用最顺手的 nlohmann/json,也要在读取后加一层校验逻辑,比如检查必要字段是否存在、数值是否在合理范围——这比换库重要得多。









