JSON 转 NDJSON 全指南:换行 JSON 怎么用,跟 JSON 数组差在哪
讲清 JSON 数组转 NDJSON 的每行一个对象格式,它在日志、流式处理、Elasticsearch 批量导入里的用途,和普通 JSON 的真实区别,以及怎么把 NDJSON 反转回数组。
JSON 转 NDJSON 全指南:换行 JSON 怎么用,跟 JSON 数组差在哪
我第一次被 NDJSON 绊住,是往 Elasticsearch 的 _bulk 接口塞数据的时候。手里是一份规规矩矩的 JSON 数组,接口却报错说格式不对。翻文档才发现,它要的不是数组,是每行一个独立 JSON 对象、行之间不加逗号的格式。那一刻我才意识到,这两种长得很像的东西,根本不是一回事。
NDJSON 全称 newline-delimited JSON,换行分隔的 JSON,也写作 JSONL 或 JSON Lines。它没有外层方括号,没有元素之间的逗号,只是一行一个完整的 JSON 值,靠换行符把它们隔开。这篇就把它讲透:它和 JSON 数组的真实区别、它在哪些场景里更好用、一段数组到底怎么转成 NDJSON,以及怎么再转回去。
NDJSON 和 JSON 数组,到底差在哪
最核心的一句话:JSON 数组是一个文档,NDJSON 是一串文档。
JSON 数组用 [ ] 把所有元素包成一个整体,元素之间用逗号隔开,整份内容是单个合法的 JSON 文档,解析器必须读完最后一个 ] 才能确认它有效。NDJSON 不一样,它的每一行都是独立的、自成一体的 JSON 值,行与行之间没有任何语法关系。你把任意一行单独拎出来,它都是合法的 JSON;但把整份 NDJSON 当成一个 JSON 文档去解析,反而会失败,因为它压根没有外层结构。
这就带来一个关键差异:NDJSON 可以逐行读,JSON 数组不行。读 NDJSON 的程序读到一行换行符就能交付一条记录,不用关心后面还有多少行;读 JSON 数组的程序得先把整份载入内存、解析完整个语法树,才敢动第一个元素。数据量小看不出差别,数据量一大,差距就是天壤之别。
每行一个独立 JSON 对象,这条规则要记牢
NDJSON 的全部规则其实就一条:每一行是一个独立的 JSON 值,通常是一个对象,行尾不带逗号,整份内容不加方括号。
举个最直观的对比。同样三条用户记录,JSON 数组长这样:
[{"id":1,"name":"小明"},{"id":2,"name":"小红"},{"id":3,"name":"小刚"}]
写成 NDJSON 就是这样:
{"id":1,"name":"小明"}
{"id":2,"name":"小红"}
{"id":3,"name":"小刚"}
注意三处变化:外层的 [ ] 没了,每个对象之间的逗号没了,每个对象各占一行。这正是新手最容易踩的坑,从数组里复制一段出来,行尾那个逗号忘了删,结果 {"id":1}, 这行解析就失败。NDJSON 每行必须是干净的独立值,逗号是数组的语法,搬到这里就成了多余的字符。
一段真实转换:JSON 数组进,NDJSON 出
光说规则不够直观,看一组真实输入输出。假设你导出了一张订单表,拿到这么一段数组:
输入(JSON 数组):
[
{"order":"A1001","amount":259,"paid":true},
{"order":"A1002","amount":88,"paid":false},
{"order":"A1003","amount":1340,"paid":true}
]
用 JSON 转 NDJSON 互转工具 切到「数组转 NDJSON」方向,输出就是:
{"order":"A1001","amount":259,"paid":true}
{"order":"A1002","amount":88,"paid":false}
{"order":"A1003","amount":1340,"paid":true}
三行,每行一个紧凑对象,没有缩进、没有逗号、没有方括号。这份输出可以直接丢进 BigQuery 的加载界面,或者粘进 Elasticsearch 的导入框,行对行的形态正好对得上加载器逐行解析的预期。整个过程在浏览器本地跑完,粘进去的数据不上传、不留日志。
NDJSON 好在哪:日志、流式、批量导入
知道了格式,再说为什么这么多场景偏爱它。
日志文件。 日志是天然的追加场景,每来一个事件就在文件尾巴上写一行。NDJSON 正好契合:采集器不需要回头改动已有内容,只管往后追加一行,文件随时都是有效的、可读的。换成 JSON 数组,每追加一条记录都得先把末尾的 ] 撬开、补逗号、再合上,既麻烦又容易写坏。
流式处理。 流式接口讲究「数据就绪就发」。一条记录算好了,服务端就能立刻刷出一行 NDJSON,客户端收到换行就处理一条,不必等整个响应结束。很多 HTTP 流式接口返回的就是 NDJSON。
大数据逐行读。 一个 5 GB 的 JSON 数组,你想看第一个对象,得先把 5 GB 全部载入内存解析完。同样的数据存成 NDJSON,读取方逐行扫,内存占用几乎可以忽略,还能在任意一行停下。这就是为什么导出、消息队列、数据管道都爱用它。
批量导入。 BigQuery 的批量加载要求换行分隔 JSON,Elasticsearch 和 OpenSearch 的 _bulk 接口说的也是 NDJSON,jq 默认就输出这种格式,pandas 的 read_json 设 lines=True 同样读它。只要某个服务让你上传 JSONL 或「每行一个 JSON 对象」,要的就是这种格式。
反转回去:NDJSON 转 JSON 数组
NDJSON 适合机器逐行吃,但人要肉眼审一份 .ndjson 日志、想折叠搜索、想丢进 JSON 查看器时,还是数组更顺手。反方向转换就是把每行一个的 JSON 值重新收拢进一个数组,再按紧凑、2 空格或 4 空格缩进美化输出。
这里有个实用细节:转换时工具逐行单独解析,遇到第一行解析不了就停下,给出从 1 起算的行号,比如「Line 83402」。一份 10 万行的导出导入失败、你完全不知道哪行坏了的时候,这个行号能让你直接跳到那一行,而不是手动二分整个文件。被跳过的空行也照样计入行号,所以你看到的数字和编辑器里对得上。
转回数组之后,如果还想进一步整理,可以接着用 JSON 格式化工具 做美化和校验,或者用 JSON 转 CSV 把结构化数据导成表格交给非技术同事。这几个工具串起来,就是一条从原始日志到可读报表的完整链路。
小结
JSON 数组是一个文档,NDJSON 是一串文档:前者适合当作整体传输和校验,后者适合追加、流式和逐行处理。记住「每行一个独立 JSON 值、不加逗号、不加方括号」这条规则,日志、流式接口、Elasticsearch 批量导入这些场景就都能对上号。需要互转时,在浏览器本地转一下,带行号定位、带分享链接,比手写脚本或记 jq 命令省心得多。
Made by Toolora · Updated 2026-06-13