直接追加数组项需先检查 key 是否存在且为数组,再 push_back;写回时用 std::ofstream 配合 std::ios::trunc 明确覆盖;大文件建议 simdjson 流式处理。

用 nlohmann::json 直接追加数组项会覆盖整个文件
直接 json["items"].push_back(...) 再 file 写入,本质是全量重写——哪怕只加一个元素,也会把原 JSON 里所有字段、注释(如果有)、空格、换行全丢掉。这不是“局部修改”,是“假装局部的全量覆盖”。
真正局部追加只在两种场景可行:文件末尾追加纯文本(如日志行),或 JSON 是数组且你只往末尾 push(但必须确保原文件就是合法数组、无根对象包裹、无尾随逗号)。
- 原文件是
{"data": [...]}?不行,不能只改data数组而不重写整个对象 - 原文件是
[{"id":1}, {"id":2}]?可以,读成数组后push_back,再整体写回(仍是全量,但语义上是“追加”) - 想保留格式/缩进/注释?nlohmann 不支持增量解析写入,别试
读-改-写是最可靠且唯一的通用做法
nlohmann 没有 json_patch 或 stream_writer 接口,所谓“局部”只能靠自己控制读写粒度。关键不是“怎么改”,而是“怎么读得准、写得稳”。
- 用
std::ifstream读整个文件到std::string,再用nlohmann::json::parse()解析——别用operator>>直接读流,它对 BOM、编码异常不鲁棒 - 修改前先检查 key 是否存在:
if (j.contains("items") && j["items"].is_array()),避免std::out_of_range - 写回时用
std::ofstream并设置std::ios::trunc,明确表达“覆盖意图”,别漏掉这个 flag - 如果原文件很大(>10MB),别硬扛;考虑用
simdjson流式解析,但 nlohmann 本身不支持
示例核心片段:
立即学习“C++免费学习笔记(深入)”;
std::ifstream f("data.json");
std::string buf((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
auto j = nlohmann::json::parse(buf); // 不是 j << f
j["items"].push_back({{"ts", time(0)}, {"val", 42}});
std::ofstream out("data.json", std::ios::trunc);
out << std::setw(2) << j << "\n"; // setw 影响缩进,不设则单行
追加失败常见错误:权限、路径、JSON 结构错位
报 std::filesystem::filesystem_error 或写入后文件变空,90% 是 I/O 层问题,不是 JSON 逻辑错。
-
std::ofstream构造失败却不检查:if (!out.is_open()) { /* 失败 */ },尤其 Windows 下路径含中文或权限不足时静默失败 - 路径写成
"./config/data.json"但当前工作目录不是预期位置——用std::filesystem::absolute()调试真实路径 - 原 JSON 末尾有逗号(
[1,2,])或注释(//),nlohmann::json::parse()默认不接受,需传nlohmann::json::parse(..., nullptr, false)关闭严格模式(但不推荐,应先清理源文件) - 多线程同时读写同一文件?没加锁就必然损坏,nlohmann 不负责同步
真要“局部写入”,得绕开 nlohmann 自己拼字符串
仅当确定原文件是纯数组、且只追加到末尾、且不要求验证合法性时,可跳过解析,直接在文件末尾插入文本。风险极高,但极少数嵌入式或日志场景需要。
- 用
std::fstream打开为std::ios::in | std::ios::out | std::ios::ate,定位到末尾 - 读最后几个字节判断是否为
]或],,决定补逗号还是直接插 - 手动构造 JSON 片段:
R"({"x":)" + std::to_string(val) + "}",注意双引号和转义 - 绝对不要用此法处理带对象、嵌套、Unicode 的数据——一个未转义的
"就让整个文件非法
这事做一次容易,维护三个月后没人敢动。除非你清楚知道为什么宁可裸写也不用 nlohmann。
真正的难点从来不在“怎么加一个元素”,而在“怎么保证加完之后,别人读它、校验它、合并它时,一切还像原来一样可靠”。格式、编码、并发、错误恢复——这些才是卡住人的地方。



















