应使用encoding='utf-8-sig':读取时自动剥离bom(\ufeff),避免列名错位或解析失败;写入时若需excel兼容才用该编码,否则坚持utf-8以保纯净。

用 open() 时指定 encoding="utf-8-sig"
CSV 文件带 BOM(\ufeff)最常见于 Windows 下用 Excel 保存的 UTF-8 文件。直接用 open(filename, encoding="utf-8") 读取,第一列字段名或首行数据开头会多出一个不可见字符,比如 "\ufeffname",导致 pandas.read_csv() 列名错位、csv.DictReader 匹配失败。
解决方法很简单:把编码从 "utf-8" 换成 "utf-8-sig"。Python 的 utf-8-sig 编码会在读取时自动剥离 BOM,写入时默认不添加 BOM(除非显式写入)。
- 对
pandas:传入encoding="utf-8-sig"即可,例如pd.read_csv("data.csv", encoding="utf-8-sig") - 对原生
csv模块:用open(..., encoding="utf-8-sig")包裹文件对象,再传给csv.reader或csv.DictReader - 注意:不要混用——如果文件实际是 GBK 或 UTF-16 编码,
utf-8-sig会解码失败并抛出UnicodeDecodeError
用 bytes 手动检测并截掉 BOM
当编码不确定,或需要兼容旧版 Python(如 2.7),或者你必须用 encoding="utf-8"(比如某些库内部强制指定),就得手动处理 BOM 字节。
UTF-8 BOM 是三个字节:b"\xef\xbb\xbf"。读取文件前先以二进制模式打开,检查开头是否匹配,再解码剩余内容。
with open("data.csv", "rb") as f:
raw = f.read()
if raw.startswith(b"\xef\xbb\xbf"):
raw = raw[3:]
content = raw.decode("utf-8")
- 这个方法绕过编码参数限制,适合封装成预处理函数
- 只适用于 UTF-8 BOM;UTF-16 BE/LE 的 BOM 是
b"\xff\xfe"或b"\xfe\xff",需额外判断 - 不推荐在 pandas 场景下使用——因为
read_csv不接受字符串内容,必须走文件路径或 file-like 对象
用 pandas 读取后修复列名中的 BOM
如果已经误用 encoding="utf-8" 读入,且第一列名变成 "\ufeffname",别急着重读。可以临时清洗列名:
df.columns = df.columns.str.lstrip("\ufeff")
- 适用于列名整体被污染,但数据行未受影响的情况
- 仅清理列名,不修复数据单元格里的 BOM(比如某列值本身以
\ufeff开头) - 更稳妥的做法是:先
df.columns = [c.strip("\ufeff") for c in df.columns],避免str.lstrip影响含\ufeff的中间位置 - 该方式是补救手段,不是源头解法——BOM 可能已污染到字符串型数据中,得逐列检查
写入 CSV 时避免生成 BOM
用 pandas.to_csv() 或 csv.writer 写入时,默认不会加 BOM。但如果你用 open(..., mode="w", encoding="utf-8-sig"),就会在文件开头写入 BOM——这常被误认为“修复了问题”,实则把 BOM 传染给了下游。
- 写入时统一用
encoding="utf-8"(无-sig),确保干净输出 - 若下游(如 Excel)要求 BOM 才能正确识别 UTF-8,应由下游负责转换,而非上游主动添加
- 用
notepad++或vim检查文件开头是否有EF BB BF字节,比肉眼更可靠
BOM 不是字符,是字节标记;它不出现在字符串长度里,也不参与正则匹配,却足以让键名匹配、JSON 解析、数据库导入全盘失效。处理它的关键不是“删掉”,而是“从第一个字节开始就拒绝它进入解码流程”。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











