📊 JSON 转 CSV 完全指南:数据结构、嵌套展开与实战技巧
2026-07-17 · 约 12 分钟
「PM 给我丢了一个 JSON 文件,说『帮导出个 Excel』」—— 这种场景做过数据分析的应该都懂。JSON 在程序员的世界里很自然,但到了业务同事手里,转成 CSV 打开才是真正的「可读」格式。
这篇文章覆盖 JSON 转 CSV 的所有常见场景:简单数组怎么转、嵌套对象怎么展开、中文乱码怎么处理、Python/JavaScript/在线工具分别怎么搞。
JSON 和 CSV 的区别
简单说:
- JSON 是「树形结构」—— 一个对象里有嵌套的对象和数组,层级可以很深
- CSV 是「表格结构」—— 行和列,扁平就好
这两种格式天然不匹配。JSON 转 CSV 的本质是 「把树拍平」。
| 特性 | JSON | CSV |
|---|---|---|
| 数据结构 | 层级嵌套 | 扁平表格 |
| 可读性(人类) | 中等 | 高(Excel 可直接打开) |
| 类型支持 | 字符串、数字、布尔、null、对象、数组 | 全是文本 |
| 文件大小 | 键重复,偏大 | 更紧凑 |
| 典型场景 | API 传输、配置文件 | 数据分析、Excel 导入/导出 |
一、最简单的场景:数组中的简单对象
最常见的 JSON 结构是一组相同字段的对象数组:
[
{ "name": "张三", "age": 28, "city": "北京" },
{ "name": "李四", "age": 32, "city": "上海" },
{ "name": "王五", "age": 25, "city": "深圳" }
]
转成 CSV 很简单,取所有键作为表头,每个对象一行:
name,age,city
张三,28,北京
李四,32,上海
王五,25,深圳
这种直接用 Python 的 csv 模块或者任意在线工具就能搞定。
💡 注意:CSV 没有类型系统。数字 28 和字符串 "28" 在 CSV 里看着一样。Excel 打开后可能会自作主张把数字变科学计数法(比如长数字 ID)。一个常用技巧是在数字前加一个 \t 前缀强制当文本处理。
二、嵌套对象怎么处理?
实际场景中 JSON 几乎不会这么工整。最常见的难题就是 嵌套 JSON 对象:
[
{
"id": "U001",
"name": "张三",
"address": {
"province": "浙江",
"city": "杭州",
"district": "西湖区"
},
"contact": {
"email": "zhangsan@example.com",
"phone": "13800138000"
}
},
{
"id": "U002",
"name": "李四",
"address": {
"province": "广东",
"city": "深圳",
"district": "南山区"
},
"contact": {
"email": "lisi@example.com"
}
}
]
这种结构不能直接转。常见的策略是 展平(Flatten):用点号连接嵌套层级作为列名。
| id | name | address.province | address.city | address.district | contact.email | contact.phone |
|---|---|---|---|---|---|---|
| U001 | 张三 | 浙江 | 杭州 | 西湖区 | zhangsan@example.com | 13800138000 |
| U002 | 李四 | 广东 | 深圳 | 南山区 | lisi@example.com |
注意第二行的 contact.phone 是空的——JSON 中缺失的字段在 CSV 里就是空值。
Python 实现:嵌套展开
import json, csv, sys
def flatten(obj, parent_key='', sep='.'):
items = []
for k, v in obj.items():
new_key = f"{parent_key}{sep}{k}" if parent_key else k
if isinstance(v, dict):
items.extend(flatten(v, new_key, sep=sep).items())
else:
items.append((new_key, '' if v is None else v))
return dict(items)
data = json.load(sys.stdin)
with open('output.csv', 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.DictWriter(f, fieldnames=flatten(data[0]).keys())
writer.writeheader()
for item in data:
writer.writerow(flatten(item))
encoding='utf-8-sig' 这个参数加了 BOM 头,Excel 打开中文就不会乱码了。
三、数组字段怎么处理?
JSON 里的数组字段更难搞。比如这个:
[
{
"order_id": "ORD001",
"items": ["苹果", "香蕉", "牛奶"]
},
{
"order_id": "ORD002",
"items": ["面包", "鸡蛋"]
}
]
数组不能直接塞进一个格子——虽然 CSV 规范允许单元格内带逗号(加引号),但这样会破坏数据的可分析性。
常见方案有三种:
- 用分隔符合并:items → "苹果|香蕉|牛奶",适合简单场景
- 转多行:每个 item 单独成行,order_id 重复,适合数据库导入
- 拆成多列:items_1, items_2, items_3...,但数组长度不一的话会有很多空列
| 方案 | 输出 | 适用场景 |
|---|---|---|
| 合并 | ORD001,"苹果|香蕉|牛奶" | 快速查看 |
| 多行 | ORD001,苹果 / ORD001,香蕉 / ORD001,牛奶 | 关系型数据库导入 |
| 多列 | ORD001,苹果,香蕉,牛奶 | 固定长度的简单数组 |
四、中文字符编码——最容易踩的坑
JSON 转 CSV 最大的坑不是转换逻辑,而是 编码。
直接生成的 CSV 用 UTF-8 编码。Excel(尤其是 Windows 上的 Excel)默认用 GBK 或 ANSI 打开文件,结果中文全变成乱码。
⚠️ 解决方案:保存 CSV 时使用 UTF-8 with BOM(utf-8-sig)。这样 Excel 能正确识别编码。Python 里就是 encoding='utf-8-sig',JavaScript 里加 \uFEFF 前缀。
用 JavaScript 在浏览器端生成并下载带 BOM 的 CSV:
function downloadCSV(data) {
const headers = Object.keys(data[0]);
const csv = [
headers.join(','),
...data.map(row =>
headers.map(h => JSON.stringify(row[h] ?? '')).join(',')
)
].join('\n');
const blob = new Blob(['\uFEFF' + csv], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'data.csv';
a.click();
}
五、JavaScript(浏览器端)一键转换
如果不想装 Python,浏览器里也能搞定。配合在线工具或者自己写个简单的 HTML 页面:
function jsonToCsv(jsonArray, flattenNested = true) {
if (!Array.isArray(jsonArray) || jsonArray.length === 0) {
return '';
}
// 展平嵌套
const flatten = (obj, prefix = '') => {
const result = {};
for (const [key, value] of Object.entries(obj)) {
const newKey = prefix ? `${prefix}.${key}` : key;
if (flattenNested && value !== null && typeof value === 'object' && !Array.isArray(value)) {
Object.assign(result, flatten(value, newKey));
} else if (Array.isArray(value)) {
result[newKey] = value.join('|');
} else {
result[newKey] = value === null ? '' : String(value);
}
}
return result;
};
const flatData = jsonArray.map(item => flatten(item));
const headers = [...new Set(flatData.flatMap(Object.keys))];
const lines = [headers.join(',')];
for (const row of flatData) {
const values = headers.map(h => {
const val = row[h] ?? '';
return /[,"\n]/.test(val) ? `"${val.replace(/"/g, '""')}"` : val;
});
lines.push(values.join(','));
}
return lines.join('\n');
}
六、在线工具一步解决
如果是偶尔用一次,写代码就大炮打蚊子了。直接用我们的免费在线工具:
粘贴 JSON → 点转换 → 下载 CSV。三步搞定。
七、一些你可能会遇到的复杂情况
情况 1:JSON 根节点不是数组?
很多 API 返回的是这种结构:
{
"status": "success",
"count": 3,
"data": [
{ "name": "张三", "score": 95 },
{ "name": "李四", "score": 87 }
]
}
需要先取出 data 数组再转。在线工具通常可以手动操作,代码里就是 json['data']。
情况 2:JSON 中 null 值怎么处理?
统一处理为空字符串。不要写 "null" 字符串,否则 Excel 里会把这个当一个叫 "null" 的文本值。
情况 3:CSV 中的特殊字符
如果字段值包含逗号、换行符或引号:
- 整个字段用双引号包裹
- 字段内的双引号替换为两个双引号
基本所有正经 CSV 工具都会自动处理这个。
情况 4:大文件转换
几万行的 JSON 浏览器端转换可能会卡。方案:
- 用 Python 脚本处理(上面的代码足够用)
- 分批转换
- 或者用 streaming parser(比如 ijson)处理几百 MB 级别的 JSON
总结
JSON 转 CSV 听起来简单,但细节挺多:
- ✅ 确保输入是 数组(不是单个对象)
- ✅ 嵌套对象用点号 展平
- ✅ 数组字段根据场景选 合并/拆行/拆列
- ✅ UTF-8 BOM 解决中文乱码
- ✅ null 和缺失字段处理成空值
- ✅ 特殊字符用 CSV 转义规则包裹
如果只是偶尔用,在线工具 是最省事的选择。如果是日常工作需要频繁转换,上面的 Python 或 JavaScript 代码可以直接用起来。