JSON 是 API 的语言,CSV 是表格、数据库和分析师的语言。两者之间的转换是日常工作 —— 把 API 响应导出到 Excel,或者把表格变成 JSON 用于导入。本指南讲解如何在 JavaScript、Python 中把 JSON 转为 CSV、再把 CSV 转回 JSON,以及如何在浏览器里即时完成;同时覆盖那些容易踩坑的边界情况(嵌套数据、引号、类型)。
核心映射:对象数组 ⇄ 行
CSV 文件是一张表:一行表头是列名,接下来一行一条记录。最自然地映射到这张表的 JSON 形态是一个 对象数组,每个对象是一行,每个键是一列。
// JSON
[
{ "id": 1, "name": "Ada Lovelace", "active": true },
{ "id": 2, "name": "Bob Khan", "active": false }
]# CSV
id,name,active
1,Ada Lovelace,true
2,Bob Khan,false表头是所有对象键的并集(这样字段不同的对象也能对齐),每一行从每一列拉取对应的值。
如何在 JavaScript 中把 JSON 转为 CSV
JavaScript 里没有内建的 JSON.toCSV,但转换本身很短。真正要做的只有 转义:任何含有逗号、双引号或换行的值都必须用双引号包起来,内部的引号要加倍。
function jsonToCsv(rows) {
if (!rows.length) return '';
const headers = [...new Set(rows.flatMap(Object.keys))];
const escape = (v) => {
if (v == null) return '';
const s = typeof v === 'object' ? JSON.stringify(v) : String(v);
return /[",\n\r]/.test(s) ? '"' + s.replace(/"/g, '""') + '"' : s;
};
const lines = [headers.join(',')];
for (const row of rows) {
lines.push(headers.map((h) => escape(row[h])).join(','));
}
return lines.join('\n');
} 注意 typeof v === 'object' 这一分支:嵌套的对象或数组没有扁平的 CSV 表达,通行的约定是把它序列化为 JSON 文本放进单元格。下文会详谈。
如何在 JavaScript 中把 CSV 转为 JSON
反过来的坑在于正确解析 CSV —— 字段可以在引号内包含逗号和换行,所以不能简单地 split(',')。用一个小型状态机(或在生产环境中用 papaparse 这种库):
function csvToJson(text) {
const rows = [];
let row = [], field = '', inQuotes = false;
for (let i = 0; i < text.length; i++) {
const c = text[i];
if (inQuotes) {
if (c === '"' && text[i + 1] === '"') { field += '"'; i++; }
else if (c === '"') inQuotes = false;
else field += c;
} else if (c === '"') inQuotes = true;
else if (c === ',') { row.push(field); field = ''; }
else if (c === '\n') { row.push(field); rows.push(row); row = []; field = ''; }
else if (c !== '\r') field += c;
}
if (field || row.length) { row.push(field); rows.push(row); }
const [headers, ...data] = rows;
return data.map((cells) =>
Object.fromEntries(headers.map((h, i) => [h, cells[i] ?? ''])));
}如何在 Python 中互转 JSON 与 CSV
Python 标准库内置了这功能 —— 无需任何依赖。
import csv, json, io
# JSON -> CSV
rows = json.loads(json_text)
buf = io.StringIO()
writer = csv.DictWriter(buf, fieldnames=list(rows[0].keys()))
writer.writeheader()
writer.writerows(rows)
csv_text = buf.getvalue()
# CSV -> JSON
rows = list(csv.DictReader(io.StringIO(csv_text)))
json_text = json.dumps(rows, indent=2)真正重要的边界情况
嵌套的对象与数组
CSV 是扁平的,JSON 不是。当值是对象或数组时有两个选择:把它在一个单元格里序列化为 JSON(简单、可逆),或者扁平化为多列,例如 address.city、address.zip(更易读,但有损且更难逆向)。如果要往返,单元格里的 JSON 更安全。
CSV 丢失类型
CSV 没有类型 —— 每个字段都是文本。从 CSV 转回 JSON 时,除非你刻意把 "1" 强转成数字,它就是字符串。要小心 007 这种值(必须保持字符串的邮编/ID),以及作为数字会丢失精度的大整数。只在往返无损时才做强转。
引号与分隔符
总是要给含逗号、引号或换行的字段加引号。某些区域设置(欧洲版 Excel 常见)使用 ; 作为分隔符 —— 如果你的 CSV 在某一列看起来不对,先检查分隔符。
键不一致
如果你的 JSON 对象并非都拥有相同的键,请用所有键的并集来构造表头,并把缺失的单元格留空 —— 不要假设第一个对象就定义了所有列。
Excel 与 UTF-8 BOM
如果你的 CSV 会在 Excel 里打开且包含非 ASCII 字符,请加上一个 UTF-8 BOM(字节 0xEF 0xBB 0xBF)。Excel 会把不带 BOM 的 UTF-8 当作老式编码读取,从而把重音字母/亚洲字符弄乱。大多数 CSV 库都有发出 BOM 的选项。
// JavaScript —— 写入 BOM,让 Excel 正确读取 UTF-8
const out = '\uFEFF' + jsonToCsv(rows);其他分隔符(CSV vs TSV vs ;)
「CSV」并不总是用逗号分隔。常见变体:
- TSV —— Tab 分隔;当值常含逗号时更安全。
- 欧洲版 Excel 在以逗号作小数点的区域使用
;作为分隔符。
如果打开后输出看起来挤在奇怪的一列里,那就是文件使用了与读取方不同的分隔符。统一一种就好(跨区域 Excel 用 , + BOM 的 CSV,工程管道用 TSV)。
面对真实世界的 CSV,请用 PapaParse
对于浏览器/Node 里来自用户的 CSV 解析,使用 PapaParse —— 它处理分隔符识别、引号字段、多行值、表头,并提供 dynamicTyping 来做数字/布尔强转。上面手写的片段对可信、简单的输入还行;面对规模,就要拿出 PapaParse。
在线把 JSON 转为 CSV —— 无需配置
对于一次性转换,可以完全跳过代码。把 JSON 贴进 fixjson 的 JSON 转 CSV 工具 并点击 To CSV,或者贴上 CSV 并点击 To JSON。它会自动处理引号、键的并集与类型强转,并完全在你的浏览器里运行 —— 不上传任何内容,这在数据包含客户记录或内部导出时很重要。
常见问题
怎样把 JSON 转为 CSV?
拿一个 JSON 对象数组,用所有键的并集构造表头,然后为每个对象写一行 —— 给任何含逗号、引号或换行的值加上引号。Python 用 csv.DictWriter,JavaScript 用一个小函数,或者直接贴到 在线工具 里。
怎样把 CSV 转为 JSON?
解析 CSV( 尊重带引号的字段),把第一行视作表头,把后续每一行映射为以表头为键的对象。注意:除非你做强转,所有值都是字符串。
嵌套的 JSON 对象在 CSV 中怎么表示?
CSV 无法嵌套,所以嵌套的对象或数组通常写为单元格里的 JSON 文本,或者扁平化为点号列,如 address.city。单元格里的 JSON 是可逆的选项。
能不能在线免费把 JSON 转为 CSV?
可以 —— fixjson 的转换器 免费双向转换,完全在浏览器里,无需账号、无需上传。
相关工具与指南
- JSON 转 CSV 工具 —— 在浏览器里双向转换
- 如何把 CSV 和 XML 转为 JSON —— 反向方向以及 XML
- 什么是 JSON? —— 转换背后的数据类型
- JSON 校验工具 —— 在转换前先检查 JSON 能否解析