python读取含bom的utf-8文件时出现乱码或多余字符,是因为utf-8编解码器不自动剥离bom(\ufeff),导致开头多出不可见字符;应改用utf-8-sig编码,它在读取时自动跳过bom、写入时可选添加bom,且对无bom文件完全兼容。

读取含BOM的UTF-8文件时为什么会出现乱码或多余字符?
Python默认用utf-8编码打开文件时,不会自动剥离UTF-8 BOM(\xef\xbb\xbf),导致开头多出三个字节,表现为或解析JSON/XML时报Unexpected UTF-8 BOM错误。
这不是Python bug,而是utf-8编解码器本身不处理BOM——它只负责字节与字符串的转换,BOM识别和剔除需显式指定或手动处理。
- 直接用
open("file.txt", encoding="utf-8")读取,BOM会保留在str开头 -
codecs.open()也一样,默认不跳过BOM - 正确做法是使用
utf-8-sig编码,它会在解码时自动剥离BOM,编码时自动写入BOM(如需)
用utf-8-sig代替utf-8是最简方案
utf-8-sig是Python内置编码别名,专为BOM场景设计:读取时忽略开头BOM,写入时可选是否带BOM(默认不写)。
无需导入codecs模块,普通open()即可:
with open("bom_file.txt", encoding="utf-8-sig") as f:
content = f.read() # BOM已自动去除,content[0]是真实首字符
- 写入时若要保留BOM(例如兼容某些Windows工具),加
encoding="utf-8-sig"即可,Python会自动在开头写入\xef\xbb\xbf -
utf-8-sig对无BOM文件完全兼容,不会误删内容 - 比手动
codecs.BOM_UTF8判断+切片更安全,避免UnicodeDecodeError或边界错误
手动用codecs模块处理BOM的适用场景
仅当需要精细控制BOM行为(比如读取时保留BOM、写入时强制不带BOM但文件原带BOM需校验)才需codecs。典型操作:
import codecs
# 读取并手动剥离BOM
with codecs.open("file.txt", "r", encoding="utf-8") as f:
raw = f.read()
if raw.startswith("\ufeff"): # \ufeff是Unicode中的BOM字符
raw = raw[1:]
# 写入时不带BOM(即使源文件有)
with codecs.open("out.txt", "w", encoding="utf-8") as f:
f.write(raw)
-
codecs.open()参数顺序是(filename, mode, encoding),注意不是open()的keyword形式 -
"\ufeff"是Unicode BOM,不是字节b"\xef\xbb\xbf",所以必须用encoding="utf-8"读出后再判断 - 用
codecs.getreader("utf-8")包装二进制流也能实现,但易出错,不推荐
常见陷阱:混淆BOM检测位置与编码声明
很多用户误以为BOM会影响# -*- coding: utf-8 -*-声明——其实它只影响运行时文件读取,跟源码编码无关。
- Python脚本自身带BOM?会导致
SyntaxError: Non-UTF-8 code starting with...,此时必须用utf-8-sig打开该.py文件,或用编辑器清除BOM - HTTP响应头声明
Content-Type: text/plain; charset=utf-8时,BOM仍可能被包含,服务端需确保响应体不含BOM,否则前端JS解析失败 - CSV用Excel打开正常但pandas报错?大概率是BOM干扰字段识别,用
pd.read_csv(..., encoding="utf-8-sig")
BOM问题本质是“谁负责剥离”——交给编码层(utf-8-sig)最稳;自己动手剥离时,务必确认数据已解码成str再操作\ufeff,而非在bytes层面硬删\xef\xbb\xbf。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











