NDJSON文件需逐行读取解析,不可一次性读取;须跳过空行、剥离BOM、捕获parse_error并记录行号,推荐复用json变量、预留string容量,并用SAX接口优化大文件处理。

NDJSON文件每行一个JSON对象,不能直接用std::ifstream一次性读整个文件
NDJSON不是单个JSON文档,而是多行独立的JSON对象(或数组),每行必须合法且互不嵌套。用json::parse()(如nlohmann/json)直接读整个文件会失败,报错类似parse error at line 1: syntax error while parsing value - invalid literal——因为第二行开头不是合法JSON续接。
正确做法是逐行读取、逐行解析:
- 用
std::string line配合std::getline()按行读,跳过空行和纯空白行 - 对每行调用
json::parse(line),捕获nlohmann::json::parse_error并记录行号(便于定位坏数据) - 不要用
std::ifstream::operator>>或std::istream_iterator,它们会按空白符分割,破坏JSON字符串内部的空格和引号
用nlohmann/json解析时,json::parse()默认不忽略BOM,Windows记事本保存的NDJSON可能出错
如果NDJSON文件由Windows记事本保存(UTF-8 with BOM),首行开头会有EF BB BF字节,json::parse()会把它当作非法字符报[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal。
解决方法很简单,在读取后手动剥离BOM:
立即学习“C++免费学习笔记(深入)”;
std::string line;
std::getline(file, line);
if (line.starts_with("\xEF\xBB\xBF")) {
line = line.substr(3);
}注意:starts_with()是C++20特性;若用C++17,改用line.size() >= 3 && line[0] == '\xEF' && line[1] == '\xBB' && line[2] == '\xBF'。
用于端到端视频本地化流程的轻量编排器,路由至四个专注子技能——/wjs-transcribing-audio、/wjs-translating-subtitles...
大文件下逐行解析性能够用,但要注意std::getline()的缓冲区管理
NDJSON常用于日志或事件流,单文件可能达GB级。标准std::getline()在默认缓冲区下对超长行(如含巨量base64字段)可能触发多次内存重分配,拖慢速度。
优化建议:
- 预先用
file.ignore(LONG_MAX, '\n')粗略估算平均行长,再用std::string line; line.reserve(8192)预留空间 - 避免在循环内反复构造
json对象;可复用同一json变量,靠赋值覆盖(j = json::parse(line)) - 若只需提取特定字段(如
"timestamp"或"level"),考虑用SAX接口(nlohmann/json的json_sax_dom_callback_parser)跳过无关结构,节省内存
遇到parse_error别直接崩溃,NDJSON允许部分失败
生产环境NDJSON常混入脏数据:某行JSON格式错误、编码不对、甚至乱码。硬性终止会导致整批数据丢失。
健壮做法是:
- 用
try { j = json::parse(line); } catch (const json::parse_error& e) { warn("line {}: {}", lineno, e.what()); continue; } - 记录错误行号和原始内容(可写入
error.ndjson供后续人工核查) - 警惕
json::out_of_range(访问不存在key)和json::type_error(类型不符),这些不属于解析阶段,需在取值时二次防护
NDJSON本质是“尽力而为”的流式格式,设计上就接受局部失败——关键是别让单行错误阻断后续所有有效数据。

















