一、映射规则其实只有三条
- JSON 的对象数组 → CSV 的每一行;对象的键 → 表头。
- 嵌套对象 → 拍平成
a.b形式的列名,例如{"user":{"name":"张三"}}变成user.name。 - 数组字段 → 序列化成字符串(用
|或分号连接),或按索引展开成tags.0、tags.1。前者适合给人看,后者适合再导入。
[{"id":1,"name":"张三","tags":["vip","new"]}]
id,name,tags
1,张三,vip|new
二、CSV 不是「逗号分隔」这么简单
真正的坑在转义。字段里出现逗号、双引号、换行时,必须用双引号包住整个字段,内部的双引号再写成两个:
id,remark
1,"含,逗号的值"
2,"他说""你好"""
3,"第一行
第二行"
自己用 split(',') 解析 CSV 一定会在这三种情况上翻车——这也是为什么应该用 csv 模块或成熟的解析库,而不是手写字符串分割。
三、Excel 会偷偷改你的数据
- 长数字变科学计数:手机号、订单号、身份证号超过 11 位就可能显示成
1.38E+17。 - 精度丢失:Excel 只保留 15 位有效数字,18 位订单号后三位直接变 0,且保存后不可恢复。
- 前导零消失:
00123变成123。
规避方式:导出时把这类列写成文本(CSV 里加 ="00123" 或前置制表符),或用「数据 → 从文本/CSV」导入并显式指定该列为文本。给机器读的文件不要用 Excel 中转一次再导出,精度已经回不来了。
四、中文与编码
CSV 用 UTF-8 保存时,Windows 版 Excel 双击打开常乱码,因为它默认按本地 ANSI(GBK) 解析。加 UTF-8 BOM(EF BB BF)就能让它识别,但某些程序会把 BOM 当成内容的一部分。取舍是:给人用 Excel 看 → 带 BOM;给程序读 → 不带 BOM。
五、代码怎么写
import csv, json
rows = json.load(open('in.json', encoding='utf-8'))
keys = sorted({k for r in rows for k in r})
with open('out.csv', 'w', encoding='utf-8-sig', newline='') as f:
w = csv.DictWriter(f, fieldnames=keys, extrasaction='ignore')
w.writeheader(); w.writerows(rows)
encoding='utf-8-sig' 就是自动加 BOM;newline='' 不加会出现空行。JS 里可以用 Papa.unparse,或手写时记得对每个字段做「含特殊字符则加引号并双写引号」的处理。
六、什么时候不该转
如果下游只是人眼查看,CSV 足够;如果要做筛选、聚合、多表关联,直接给 Excel 或导入数据库更合适;如果结构嵌套超过两层,CSV 的列名会爆掉,此时应该拆成多张表(主表 + 子表)而不是硬拍平。
日常小批量转换用 JSON 与 CSV 互转 最快,本地完成、数据不外传;转完想确认 JSON 是否合法,用 JSON 格式化校验 过一遍。
小结
对象数组转行、嵌套拍平成 a.b、数组序列化;CSV 的特殊字符必须加引号并双写引号;Excel 会把长数字改成科学计数并丢精度;给人看加 BOM,给机器读不加。