Python 文件编码错误 UnicodeDecodeError

FreeGuideOnline 最新 2026-07-05

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd5 in position 0: invalid continuation byte


这就是典型的 **UnicodeDecodeError**,它表示 Python 在尝试将文件中的字节流解码成字符串时,遇到了无法按照当前编码规则解释的字节。本教程将带你从零开始理解并彻底解决这个错误。

---

### 什么是 UnicodeDecodeError

计算机中存储的都是字节(byte),而我们看到的文字是字符(character)。把字节转换成字符的过程叫做 **解码**(decode),把字符转换成字节叫 **编码**(encode)。

Python 3 的字符串类型 `str` 内部使用 Unicode 表示,当你用 `open()` 读取文本文件时,Python 必须将磁盘上的原始字节根据某个编码(如 UTF-8、GBK、Latin-1 等)解码成字符串。如果文件的实际编码与 Python 使用的编码不一致,就会抛出 `UnicodeDecodeError`。

关键词:**编码不匹配**。

---

### 常见触发场景

1. **未指定 encoding 参数,使用了默认的 UTF-8 或系统地区编码**
   ```python
   with open('data.txt', 'r') as f:
       content = f.read()   # 文件实际是 GBK,但 Python 可能用 cp1252 或 utf-8 解码
  1. 打开来自其他操作系统的文件,尤其是中文 Windows 下生成的文本文件默认是 GBK,而 Linux/macOS 下默认 UTF-8。

  2. 文件头部包含非标准字符,例如带有 BOM 的 UTF-8 文件在部分工具中可能被误读。

  3. 文件不是纯文本,而你试图以文本模式打开图片、PDF 等二进制文件。


解决方法

1. 指定正确的编码

最直接的解法是告诉 open() 文件的实际编码。

# 文件是 GBK 编码
with open('data.txt', 'r', encoding='gbk') as f:
    content = f.read()

如何知道文件编码?

  • 查看文件来源:若是从某个特定系统导出,通常有固定编码。
  • 用文本编辑器(如 VS Code、Notepad++)打开,右下角一般会显示编码。
  • 使用 Python 的 chardet 库自动检测(见下文)。

2. 使用 errors 参数处理无法解码的字节

如果无法完全确定编码,或文件只有少量损坏字节,可以通过 errors 参数设置解码异常处理策略。

  • 'ignore':直接跳过无法解码的字节

    with open('data.txt', 'r', encoding='utf-8', errors='ignore') as f:
        content = f.read()
    

    注意:会静默丢失数据,可能破坏文本完整性。

  • 'replace':用替换字符 (U+FFFD) 替代无法解码的字节

    with open('data.txt', 'r', encoding='utf-8', errors='replace') as f:
        content = f.read()
    

    这种方式更适合调试,可以清楚看到哪些位置出现了问题。

  • 'backslashreplace':将无法解码的字节转成 \x 形式的转义序列,例如 \xd5

3. 使用 chardet 智能探测编码

chardet 是一个第三方库,可以自动猜测文件编码,准确率较高。安装:

pip install chardet

使用示例:

import chardet

# 以二进制模式读取文件的一部分来检测编码
with open('data.txt', 'rb') as f:
    raw_data = f.read()

result = chardet.detect(raw_data)
encoding = result['encoding']  # 例如 'GB2312' 或 'Windows-1252'
confidence = result['confidence']

print(f"Detected encoding: {encoding} with confidence {confidence}")

# 用检测到的编码打开文件
with open('data.txt', 'r', encoding=encoding) as f:
    content = f.read()

对于大文件,只需读取前几 KB 即可准确检测。

4. 以二进制模式读取并手动处理

当你需要完全控制解码过程时,可以先用二进制模式 'rb' 读取,再通过字节对象的 decode 方法分段处理。

with open('data.txt', 'rb') as f:
    raw_bytes = f.read()

# 尝试多种编码
for enc in ['utf-8', 'gbk', 'latin-1', 'cp1252']:
    try:
        text = raw_bytes.decode(enc)
        print(f"Success with {enc}")
        break
    except UnicodeDecodeError:
        continue

你也可以配合 try...except 只对出错的部分做替换。

5. 处理带 BOM 的 UTF-8 文件

某些编辑器会在 UTF-8 文件开头添加 BOM(字节顺序标记 EF BB BF),这会导致 utf-8 解码时在字符串开头出现一个额外的零宽字符 \ufeff。可以指定 encoding='utf-8-sig' 自动处理。

with open('bom_file.txt', 'r', encoding='utf-8-sig') as f:
    content = f.read()  # BOM 会被自动移除

最佳实践

  1. 总是显式指定 encoding 参数
    不要依赖默认编码,避免环境差异导致的问题。

    with open('file.txt', 'r', encoding='utf-8') as f:
        ...
    
  2. 将数据统一转换为 UTF-8
    如果需要在不同系统间交换数据,优先使用 UTF-8 编码保存文件。

  3. 在脚本开头声明编码一致性
    如果你的 Python 文件本身就包含非 ASCII 字符,文件开头的 # -*- coding: utf-8 -*- 也要与实际保存编码一致。

  4. 使用 pathlib 时同样注意编码

    from pathlib import Path
    text = Path('file.txt').read_text(encoding='utf-8')
    
  5. 日志或调试时捕获异常

    try:
        with open('data.txt', 'r', encoding='utf-8') as f:
            content = f.read()
    except UnicodeDecodeError as e:
        print(f"Decode error at position {e.start}: {e.reason}")
        # 回退到其他编码或 errors 处理