UnicodeDecodeError: 'utf-8' codec can't decode byte 文件编码排查与解决
报错与症状
打开文本文件时撞到:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd6 in position 0: invalid continuation byte
0xd6 这类高位字节是 GBK / GB2312 中文的典型特征——用 utf-8 的视角去读它,自然读不懂。
触发环境
- Python 3.13.12(本机实测,Windows 11)
- 一个用 GBK 编码保存、却用 utf-8 打开的文本文件
- 跨平台文件交换(Windows 默认 GBK、Linux / macOS 默认 utf-8)最易踩
根因分析
Python 3 里 open(path, "r") 默认 encoding="utf-8"。utf-8 是变长编码:一个中文字符占 3 字节,且每字节有严格的高位标记规则;而 GBK 中一个中文占 2 字节,字节值与 utf-8 不兼容。
当文件实际是 GBK,字节流里出现 0xd6 0xd0 这种组合,utf-8 解码器在 position 0 就发现「这不是合法的 utf-8 续接字节」,于是抛出 invalid continuation byte。根因是编码假设错误,不是文件损坏。
最小复现(可运行)
# 运行环境:Python 3.13.12 / Windows 11
import tempfile, os
path = tempfile.mktemp(suffix=".txt")
with open(path, "w", encoding="gbk") as f: # 故意用 GBK 写
f.write("中文测试数据,包含特殊字符:你好世界")
try:
with open(path, "r", encoding="utf-8") as f: # 却用 utf-8 读
data = f.read()
print("utf-8 读取成功:", data)
except UnicodeDecodeError as e:
print("捕获到 UnicodeDecodeError:", repr(e))
os.remove(path)
终端输出(实测)
捕获到 UnicodeDecodeError: UnicodeDecodeError('utf-8', b'\xd6\xd0\xce\xc4\xb2\xe2\xca\xd4\xca\xfd\xbe\xdd\xa3\xac\xb0\xfc\xba\xac\xcc\xd8\xca\xe2\xd7\xd6\xb7\xfb\xa3\xba\xc4\xe3\xba\xc3\xca\xc0\xbd\xe7', 0, 1, 'invalid continuation byte')
解决方法
1. 用正确的 encoding 打开(首选,能拿到真数据)
with open(path, "r", encoding="gbk") as f:
data = f.read()
print(data) # 中文测试数据,包含特殊字符:你好世界
2. errors='replace' / 'ignore'(兜底,会丢信息但要先跑通)
with open(path, "r", encoding="utf-8", errors="replace") as f:
data = f.read()
print(data) # 乱码:�����������������ַ������������
errors="replace" 会把无法解码的字节替换成 �,程序不崩但内容已失真,只适合「先跑通流程、稍后定位编码」的临时场景,不能当正式解法。
预防措施
- 写文件时显式指定 encoding,别依赖平台默认值:
open(path, "w", encoding="utf-8")。 - 读来源不明的文件,先用
charset-normalizer探测真实编码,再决定用哪个encoding打开。 - 全程统一用 utf-8(写、读、数据库、HTTP 响应),可以从根本上消灭这类问题。
本文环境:Django 4.2 / Python 3.11 / Ubuntu 22.04
广告位占位 · post-inline