一、乱码的真正原因
CSV 文件本身不含「我用什么编码」的声明,Excel 只能猜:有 BOM 就按 UTF-8 读,没有 BOM 就按系统本地编码(简体中文 Windows 是 GBK/ANSI)读。
所以一份无 BOM 的 UTF-8 文件,被 Excel 用 GBK 解析,中文就全乱了。反过来,一份 GBK 文件在 Mac 的 Numbers 里也可能乱。
二、三种解法,按场景选
方法一:写文件时加 UTF-8 BOM
BOM 是文件开头的三个字节 EF BB BF,专门用来告诉 Windows「我是 UTF-8」。Python 里用 encoding='utf-8-sig' 即可:
open('out.csv', 'w', encoding='utf-8-sig', newline='')
缺点是有些程序(老版本 PHP、部分 JSON 解析器)会把 BOM 当成内容,导致「第一个字段名多了看不见的字符」。给 Excel 看的文件加,给程序读的不加。
方法二:用「数据 → 从文本/CSV」导入
不要双击打开,走导入向导,在「文件原始格式」里选 65001 : Unicode (UTF-8),再指定分隔符。这样不改文件也能正确显示,适合只读一次的场景。
方法三:另存为 ANSI
用记事本打开 → 另存为 → 编码选 ANSI(GBK)。文件变小、Excel 双击正常,但只能容纳 GBK 字符,emoji 和生僻字会丢。仅适合纯中文内网场景。
三、长数字为什么会变样
Excel 把「看起来像数字」的内容自动转成数值,于是:
| 原始值 | Excel 显示 | 后果 |
|---|---|---|
| 13800138000 | 1.38E+10 | 列宽不够时显示为科学计数,值本身还在 |
| 110101199001011234 | 110101199001011000 | 超过 15 位,后三位被抹成 0,保存后不可恢复 |
| 00123 | 123 | 前导零丢失 |
| 2026-11-03 | 2026/11/3 | 变成日期格式 |
前两种最容易出事故:一份用户表用 Excel 打开再另存,身份证号就永久损坏了。
规避方式:
- 导出时把这类字段写成文本,CSV 里用
="110101199001011234"包一层,Excel 会当公式返回字符串。 - 或导入时在向导里把该列类型设为「文本」。
- 或在值前加一个制表符/单引号(会显示出来,不太美观)。
- 最稳的做法:这类数据不要用 Excel 中转,直接用脚本处理。
四、还有两个小坑
- 分隔符:某些地区设置下 Excel 默认用分号而不是逗号,打开后整行挤在一列。导入时手动选逗号即可。
- 多行字段:字段内部含换行时,CSV 规范要求用双引号包裹。Excel 能正确识别,但自己写脚本解析时容易切错行。
五、一条稳妥的工作流
生成 → 明确编码(给人看加 BOM)→ 关键字段当文本 → 导入向导确认类型 → 检查首尾几行和长数字列 → 再分发。
需要把 JSON 转成表格时,用 JSON 与 CSV 互转 直接导出;转换前先确认字段里有没有逗号和换行,必要时选择引号包裹模式。
小结
乱码 = Excel 猜错编码,加 BOM 或走导入向导指定 UTF-8;长数字变 0 是 15 位精度限制,必须在导出时声明为文本;关键数据别用 Excel 打开再另存。