跳到主要内容

JSON 转 CSV 完整指南:扁平化、数组处理与 Excel 中文不乱码

把接口返回的 JSON 数组转成能直接拖进 Excel 的 CSV,讲清嵌套对象扁平化、数组导出、分隔符选择,以及 Windows 版 Excel 中文乱码用 UTF-8 BOM 解决的全过程。

发布于 作者 李雷
#JSON 转 CSV #数据导出 #Excel #数据分析 #RFC 4180

JSON 转 CSV 完整指南:从接口响应到能用的表格

后端给出的数据几乎都是 JSON,而运营、财务、市场这些岗位的同事只认 Excel 和 Google Sheets。中间这道转换,看起来一行脚本就能搞定,真做起来却全是坑:嵌套对象怎么落成列、数组要不要展开、分号还是逗号、为什么中文一进 Excel 就成了天书。这篇把这几件事一次讲透。

为什么要把 JSON 转成 CSV

最常见的三个场景:把 /api/orders 这类接口的返回直接导给运营看;把抓来的接口数据落成表交给分析师做透视;把埋点结果整理成明细给产品经理。CSV 的好处是任何表格软件都能打开,不依赖任何库,文件体积小,还能直接进数据仓库。坏处是它天生是二维的,而 JSON 是树形的,所以转换的核心难点就是:怎么把一棵树压平成一张表。

嵌套对象怎么扁平化

JSON 里 {"address": {"city": "London"}} 这种结构,没有一个天然对应的 CSV 列。通行做法是用点号展开成 address.city 这样的列名。这是 pandas、jq 和大多数 BI 工具导入时约定俗成的写法,分析师一看就懂。

如果你不想展开,可以关掉扁平化,整个嵌套对象会作为一个 JSON 字符串塞进单个单元格,保持无损、可再解析。两种策略各有用途:要做数据透视就展开,要原样留档就保留 JSON。比如对两个环境的配置做 diff,把 {"db":{"pool":{"max":20}}} 展开成 db.pool.max 列,值是 20,左右一排就能逐项对比,比盯着两坨深缩进的 JSON 省事得多。

数组值的两种导出方式

数组比对象更麻烦。"interests": ["design", "code", "ops"] 这种标量数组有两条路:一是当成 JSON 字符串原样保留成 ["design","code","ops"],无损但表格里难读;二是用分隔符连接成 design | code | ops,好读但有损。问卷多选题用第二种,落档备份用第一种。

有一条边界要记住:如果数组里装的是对象,无论你选哪种,工具都会回退成 JSON 字符串。因为含对象的数组没法无损地塞进一个单元格,强行连接只会悄无声息丢掉结构。真要把这些嵌套字段拆成列,得先在转换前把 JSON 改造成每个对象的字段都落在行这一层。

分隔符、转义与 RFC 4180

CSV 没有官方标准,但 RFC 4180 是事实上的规范。它规定:字段里如果含逗号、双引号或换行,整个字段要用双引号包起来,内部的双引号要翻倍写成两个。一个像 he said "hi", ok 的值,正确的 CSV 输出是 "he said ""hi"", ok"。这套转义不做对,导进表格就会串列,这是 JSON 转 CSV 最容易翻车的地方。

分隔符也不是只有逗号。德语区和部分欧洲地区的 Excel 默认认分号,数据本身含逗号时换成 Tab 或竖线更干净。好的工具应该让你在逗号、分号、Tab、竖线之间随便切。

中文进 Excel 变乱码:UTF-8 BOM 的事

这是国内用户被坑得最多的一条。CSV 文件本身存的是正确的 UTF-8 字节,但 Windows 版 Excel 打开 CSV 时会自己猜编码,经常猜成系统区域编码(GBK),于是 商品名称 就成了 鍟嗗搧 这种乱码。

解决办法是在文件开头加 3 个字节的 UTF-8 BOM(字节序标记 EF BB BF)。这 3 个字节等于明确告诉 Excel:我是 UTF-8,别猜了。加上之后中文立刻正常。要注意 Google Sheets、Numbers 和现代文本编辑器不需要 BOM,给它们导出时反而别加,所以最好是一个可开关的选项,而不是默认强塞。

一个真实的输入输出例子

输入这段 JSON:

[
  {"name": "张三", "address": {"city": "上海"}, "tags": ["vip", "新客"]},
  {"name": "李四", "address": {"city": "北京"}}
]

开扁平化、数组用 | 连接、逗号分隔、带表头,转出来的 CSV 是:

name,address.city,tags
张三,上海,vip | 新客
李四,北京,

注意三个细节:address.city 是嵌套展开来的;tags 数组被连接成了一格;第二条记录没有 tags,那一列就留空对齐,而不是错位。列顺序取的是所有对象 key 的并集,按首次出现顺序排,字段不齐也不会串行。

我自己踩过的坑

我第一次给运营导订单数据,直接把接口返回的 {"data": [...]} 整个粘进去,结果转出来只有一行,把顶层那个对象当成了一条记录。后来才反应过来,要粘的是里面那个数组本身 [...],顶层得是对象数组才能干净映射成行。还有一次没勾 BOM,运营截图问我"你这表怎么全是乱码",我盯着自己电脑上好端端的文件愣是没复现,因为我用的是 Numbers。这两个坑现在每次转之前都会先想一遍。

需要反向操作,把 CSV 转回 JSON,用 csv-to-json 即可,两者参数空间一致、可来回切换。转之前如果想先格式化、校验一下 JSON 是否合法,可以先过一遍 json-formatter。本文用到的转换工具在这里:json-to-csv,全程浏览器本地,数据不出页面。


Made by Toolora · Updated 2026-06-13