优先试 encoding='utf-8-sig',因windows excel导出的csv几乎都带bom,用默认utf-8读会将\ufeff残留为列名前隐形字符导致keyerror;utf-8-sig可自动跳过bom且兼容excel,写入时也需配对使用。

pd.read_csv() 读取中文 CSV 时乱码,优先试 encoding='utf-8-sig'
Windows 上 Excel 导出的 CSV 文件几乎都带 BOM(\ufeff),用默认 utf-8 读会把 BOM 当作真实字符塞进第一列列名里,比如打印 df.columns[0] 是 '姓名' 而不是 '姓名',后续 df['姓名'] 直接报 KeyError。utf-8-sig 是 Python 内置编码别名,能自动跳过 BOM,且写入时也默认加 BOM,对 Excel 打开最友好。
常见错误包括:
- 漏写
encoding参数 → pandas fallback 到系统编码(如gbk),遇到 UTF-8 BOM 文件直接UnicodeDecodeError - 写了
encoding='utf-8'→ BOM 残留,列名或首行数据开头多出隐形字符 - 写成
UTF-8或utf8→ 大小写敏感,且必须带-sig后缀才生效
不确定编码时,用 chardet 探测再传给 pd.read_csv()
不是所有中文 CSV 都是 utf-8-sig。老版 Windows 记事本、某些 ERP 系统导出的文件更可能是 gbk 或 gb2312;Mac Numbers 导出的偶尔是 mac-roman。硬猜容易失败,先探测:
import chardet
with open('data.csv', 'rb') as f:
raw = f.read(10000)
print(chardet.detect(raw))
# 输出类似 {'encoding': 'gbk', 'confidence': 0.99}
拿到结果后直接塞进 pd.read_csv():
-
encoding='gbk':国内大多数 Excel/记事本导出的简体中文 CSV -
encoding='utf-8-sig':VS Code、Python 脚本生成或 Excel「另存为 CSV UTF-8」的文件 -
encoding='latin-1':兜底选项,不会报错,但中文变乱码,可辅助判断是否真为gbk
用 csv 模块手动读取时,encoding 必须在 open() 层指定
csv.reader 和 csv.writer 本身不接受 encoding 参数,必须在 open() 时声明,否则 BOM 不会被跳过:
import csv
# ✅ 正确:BOM 在 open 时被 utf-8-sig 自动处理
with open('data.csv', encoding='utf-8-sig') as f:
reader = csv.reader(f)
for row in reader:
print(row) # 第一列列名干净,无 \ufeff
<h1>❌ 错误:open 用 utf-8,BOM 还在,csv.reader 读到的就是脏数据</h1><p>with open('data.csv', encoding='utf-8') as f:
reader = csv.reader(f) # row[0] 开头仍含 \ufeff
</p>
注意:codecs.open() 已没必要,Python 3.7+ 原生 open() 完全支持 utf-8-sig。
df.to_csv() 导出中文 CSV 给 Excel 用,必须用 encoding='utf-8-sig'
即使读取时用了 utf-8-sig,导出时不显式指定也会乱码。Excel 默认按 BOM 判断编码,纯 utf-8 文件没 BOM,它就当 ANSI(即 gbk)解析,中文全变 æ³å。
正确写法:
df.to_csv('out.csv', encoding='utf-8-sig', index=False)
关键点:
- 不能省略
encoding,也不能用utf-8 -
index=False避免多出一列索引,尤其和中文列混排时易错位 - 如果目标用户用旧版 Excel 或 WPS,
gbk也可行,但兼容性不如utf-8-sig
BOM 是隐形但高频的坑,很多人花半小时调 errors='ignore' 或正则清洗列名,其实只差一个 -sig。真正麻烦的是混合编码——比如某列是 gbk,另一列是 utf-8,这种得拆开处理,不在 encoding 参数能覆盖的范围里。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











