元数据
| id | python-unicode-decode | 收录 | 2026-08-29 |
|---|---|---|---|
| 问题域 | 编码代理与终端 | 主题分组 | 编码与格式 |
| 适用工具 | python · 外部工具 | ||
症状
`open(path).read`、`pandas.read_csv(path)`、`configparser` 等读文件时直接抛异常:
```
UnicodeDecodeError: 'gbk' codec can't decode byte 0xad in position 2: illegal multibyte sequence
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd6 in position 0: invalid continuation byte
```
特征:**Windows 中文环境**(默认 GBK/cp936)读 UTF-8 文件报 `'gbk' codec can't decode`——最常见;Linux/mac(默认 UTF-8)读 GBK/旧文件报 `'utf-8' codec can't decode`;文件是别人发的/从旧系统拷来的/Excel 另存的(GBK 或 GB18030);`file xxx` 显示 ISO-8859 之类(非 UTF-8)。
原因
`open` 不指定 `encoding` 时用**系统默认编码**:Windows 中文版是 GBK(cp936),Linux/mac 是 UTF-8。文件实际编码 ≠ 默认编码时,解码到第一个非 ASCII 字节就抛 UnicodeDecodeError。这是「文件编码」与「读取环境」不匹配,不是文件坏了,也不是代码逻辑错。
解法
1. **先看文件真实编码**:`file xxx.txt`(输出 UTF-8 / ISO-8859(GBK)/ GB18030 等),或 `xxd xxx.txt | head` 看字节。
2. **读时显式指定 encoding(正解)**:
- 读 GBK 文件:`open(path, encoding='gbk')`(GB18030 更全:`encoding='gb18030'` 兼容 GBK 且不丢生僻字);
- 读 UTF-8 文件:`open(path, encoding='utf-8')`(在 Windows 上也稳);
- pandas:`pd.read_csv(path, encoding='gbk')`。
3. **统一转码(治本,适合批量)**:`iconv -f gbk -t utf-8 old.txt > new.txt`(或 Excel 里另存为 UTF-8);项目里约定所有文本文件统一 UTF-8。
4. **兜底容忍**:`open(path, errors='replace')` 或 `errors='ignore'` 不抛异常——但坏字节变 `�`,**内容不可逆丢失**,只适合日志/非关键解析。
5. **stdout 也乱码时**:print 中文在 GBK locale 下输出乱码,加 `PYTHONIOENCODING=utf-8`(或 `sys.stdout.reconfigure(encoding='utf-8')`)——那是输出编码问题,与读取分开排查。
验证证据
- 本地实测(2026-08-29,WSL Ubuntu,python 3.14.4;UTF-8 文件与 GBK 文件各一,iconv 生成):
- 复现 A(Linux 视角):默认读 GBK 文件 → `UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd6 in position 0: invalid continuation byte`(exit 1);
- 复现 B(Windows 中文视角):`LC_ALL=zh_CN.GBK`(localedef 生成该 locale)读 UTF-8 文件 → `UnicodeDecodeError: 'gbk' codec can't decode byte 0xad in position 2: illegal multibyte sequence`(exit 1)——与 Windows 用户报错原文一致;
- 修复 A:`encoding='gbk'` 读 GBK 文件 → 正常输出「中文测试行」(exit 0);
- 修复 B:GBK locale 下 `encoding='utf-8'` 读 UTF-8 文件 → 正常(exit 0;配合 PYTHONIOENCODING=utf-8 stdout 无乱码);
- 兜底:`errors='replace'` → 不抛异常(exit 0)但中文变 `�`(不可逆,演示「容忍≠保真」)。
- 实测复现日志(2026-08-29)
来源与证据
素材来源:https://github.com/TitorX/Postdown/issues/7
验证证据:Evidence details kept locally (2026-08-29)