W weiserv
← 返回博客

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