跳到主要内容

JSON Lines (JSONL) 格式化与逐行校验指南

讲清楚 JSON Lines 每行一个对象的写法、它和 JSON 数组的区别, 以及怎么逐行校验找出具体哪一行出错, 适合处理日志、流式数据和机器学习训练样本。

发布于 作者 李雷
#JSON Lines #JSONL #NDJSON #数据格式 #日志分析

JSON Lines (JSONL) 格式化与逐行校验指南

我第一次被 JSONL 坑, 是导出一份 50 万行的埋点日志想灌进分析脚本。我习惯性地用解析整份 JSON 的方式去读它, 结果立刻报错。后来才反应过来, 这根本不是一个 JSON 数组, 而是 JSON Lines, 每一行才是一个独立的 JSON 值。这篇文章把这个格式讲透, 也讲清楚怎么逐行校验, 不让一行坏数据废掉整份文件。

JSON Lines 到底是什么

JSON Lines 也写作 JSONL, 有时候叫 NDJSON (Newline Delimited JSON)。规则很简单: 一行存一个完整的 JSON 值, 行与行之间用换行符隔开。例如:

{"id": 1, "event": "login", "ok": true}
{"id": 2, "event": "click", "ok": true}
{"id": 3, "event": "logout", "ok": false}

注意它没有外层的 [ ], 行尾也没有逗号。每一行单独拿出来都能被标准 JSON 解析器读懂, 这正是它的设计意图。

它和 JSON 数组的区别

很多人会把这两种格式搞混。一个标准的 JSON 数组长这样:

[
  {"id": 1, "event": "login"},
  {"id": 2, "event": "click"}
]

差别在于读取方式。JSON 数组必须等整份内容下载或读完, 解析器才能给出结果, 因为它要看到收尾的 ] 才算合法。JSON Lines 不需要, 你读到一行就能解析一行, 这就是它最大的优势: 每行独立, 可以流式处理。一份 10 GB 的 JSONL 文件, 你可以一边读一边处理, 内存里永远只放当前这一行。换成 JSON 数组, 你得先把 10 GB 全装进内存。

为什么这么多场景在用它

JSONL 之所以常见, 是因为它天生适合"一条一条到来"的数据:

  • 日志与事件流: 服务每产生一条记录就追加一行, 不需要回头改文件结尾, 写入是纯追加。
  • 大数据与流式管道: Kafka、Spark、BigQuery 的导入导出都偏好按行切分, 方便并行。
  • 机器学习训练数据: 很多数据集就是一行一个样本 (prompt/completion 对、标注记录), 训练时按行喂入。
  • 数据库与表格导出: 把查询结果按行落盘, 后续脚本逐行消费即可。

它们的共同点是: 数据不是一次成型的整体, 而是不断累积的记录。

逐行校验: 关键在于不被一行拖垮

JSONL 真正的痛点是排错。当文件有几十万行, 其中第 472 行少了一个引号, 用整份解析的工具只会甩给你一句 "Unexpected token", 然后什么都读不出来。前面 471 行明明都是好的, 却一起陪葬。

正确的做法是逐行解析: 把每一行当作独立的 JSON 值去 parse, 哪一行失败就单独记下它的行号和报错原因, 其余有效行照样保留。这样你既能定位坏行, 又不丢有效数据。

举个真实例子。下面这段 JSONL 第二行末尾多了一个逗号:

{"user": "amy", "score": 91}
{"user": "ben", "score": 88},
{"user": "cara", "score": 95}

逐行校验的结果会是这样:

  • 第 1 行: 有效, {"user":"amy","score":91}
  • 第 2 行: 无效, Unexpected token , in JSON (行尾那个逗号是数组写法, JSONL 里不该有)
  • 第 3 行: 有效, {"user":"cara","score":95}

第 1 行和第 3 行依然能拿去格式化或导出, 你只需要回头修第 2 行。这正是 JSON Lines 格式化工具 的核心: 粘贴进去, 按需跳过空行, 然后看到每一行的解析结果, 有效行可以重新格式化成 pretty JSONL、转成 JSON 数组, 或在记录是对象时展开成 CSV-like 表格逐字段检查。

三种常用转换

处理完校验, 通常还要做格式转换:

  1. 转 JSON 数组: 把有效行合并成一个标准数组, 方便丢给只认数组的下游脚本或测试 fixture。如果你接下来要对单个对象做缩进美化, 可以接着用 JSON 格式化工具 继续整理。
  2. 展开成表格: 当每行都是字段相近的对象时, 按 key 生成列, 一眼看出哪条记录缺字段、哪条类型不对。需要进一步把表格和 CSV 互转时, CSV 转 JSON 工具 能补上另一半流程。
  3. 重新格式化 JSONL: 把杂乱缩进的输入统一成整齐的一行一对象, 方便 diff 和 code review。

几个容易踩的坑

  • 别给 JSONL 套上外层 [ ], 也别在行尾加逗号, 那是数组语法, 会让逐行解析失败。
  • 表格模式只对对象记录有意义, 纯数组或基本值 (数字、字符串) 生成不了有列名的表。
  • 空行通常不该被当成数据, 校验前选择跳过空行, 免得报一堆无意义的错误。

把"每行独立"这件事记牢, JSONL 处理起来其实比 JSON 数组更省心。下次面对一份巨大的日志或训练数据, 先逐行校验定位坏行, 再按需转数组或表格, 整个流程会清爽很多。


Made by Toolora · Updated 2026-06-13