跳到正文
效率工具实用笔记关于本站
文件整理

读取UTF-8文本文件:read_text和编码错误排查

约 7 分钟阅读AI 辅助整理

用自建UTF-8文件演示Path.read_text显式指定encoding,区分文件不存在与编码不匹配两类报错,并说明为什么不用errors=ignore掩盖数据。

本文要点

  1. 先造一个练习文件,内容自己写,保存时选 UTF-8 编码

  2. read_text 的 encoding 参数是可选的,但“可选”不等于“可以不管”

  3. 第一类常见报错是文件找不到

读取UTF-8文本文件:read_text和编码错误排查的知识要点示意图
依据已审核正文摘取要点制作的示意图,非实物照片;请结合正文中的条件与范围阅读。要点摘自已审核正文;完整条件与说明见正文。查看高清图解 ↗
本文目录

先决定用哪个方法:read_text适合一次读完的文本

如果你要读的是一个自己写的纯文本文件,想一次性拿到整段字符串,Path.read_text 就是为这个场景准备的。按 pathlib 文档的说明,read_text(encoding=None, errors=None, newline=None) 返回所指向文件解码后的内容,类型是字符串;文件会被打开然后关闭。

它和 Path.read_bytes 的分工很清楚:read_text 返回 str,read_bytes 返回 bytes。你要处理的是文字,就用 read_text;你要处理的是二进制内容,才用 read_bytes。

本文只处理一个自建场景:练习目录里有一个你自己保存为 UTF-8 的文本文件,用 read_text 读出来,并排查读不到或读错的两类问题。所有文件都是练习用的自建示例,不涉及真实业务数据。动手前请把练习文件放在单独目录,例如 exercise/,不要拿重要文件直接试。

自建UTF-8文件:先写进去,再读出来

先造一个练习文件,内容自己写,保存时选 UTF-8 编码。下面这段只操作练习目录里的文件:

from pathlib import Path

p = Path("exercise/notes_utf8.txt")
p.write_text("第一行:练习文本\n第二行:继续练习\n", encoding="utf-8")
print(p.read_text(encoding="utf-8"))

输入是这段自建文本,输出是读回来的字符串。write_text 和 read_text 都显式写了 encoding="utf-8",两边保持一致,这是避免编码问题的第一步。

为什么两边都要写:写入时用什么编码,决定文件里实际存了哪些字节;读取时用什么编码,决定这些字节被还原成哪些字符。两边不一致,读出来的字符就可能对不上。

注意 write_text 会覆盖同名文件。练习时用一个专门的新文件名,不要指向你已有的重要文件。

encoding不写会怎样:默认值不等于UTF-8

read_text 的 encoding 参数是可选的,但“可选”不等于“可以不管”。文档说明这些可选参数与内置 open() 的含义相同,而 open() 在不指定 encoding 时使用的是平台相关的默认编码,并不保证是 UTF-8。

这意味着:同一个 UTF-8 文件,在一台默认编码是 UTF-8 的机器上读可能正常,换到默认编码不同的环境里读就可能报错或读出乱码。

所以对“读取 UTF-8 文本文件”这个任务,稳妥的写法是显式写 encoding="utf-8",而不是依赖默认值。显式写出来,读的行为就不随运行环境变化。

本节只说明为什么要显式指定编码,不涉及其他编码之间的转换。

文件不存在:FileNotFoundError怎么定位

第一类常见报错是文件找不到。如果你写的路径指向的文件实际不存在,read_text 会抛出 FileNotFoundError。

排查顺序可以这样走(以下为编辑整理的检查方向):

1. 确认路径字符串和你实际的文件位置是否一致,注意目录名和文件名的大小写。

2. 确认当前工作目录是不是你以为的那个目录。相对路径是相对于程序运行时的工作目录,不是相对于脚本文件所在目录。

3. 用 Path.exists() 先判断一次,再决定是否读取。

from pathlib import Path

p = Path("exercise/notes_utf8.txt")
if p.exists():
    print(p.read_text(encoding="utf-8"))
else:
    print("文件不存在:", p)

按文档说明,exists() 在路径指向存在的文件或目录时返回 True,路径无效、不可访问或缺失时返回 False。先判断再读,能把“路径写错”和“编码不对”这两类问题分开,不至于混在一起猜。

编码不匹配:UnicodeDecodeError说明字节对不上

第二类报错是编码不匹配。文件里的字节不是按你指定的编码写成的,读取时解码就会失败,抛出 UnicodeDecodeError。

典型情形:文件实际是 GBK 等其他编码保存的,你却用 encoding="utf-8" 去读。这时报错信息会指出在哪个字节位置解码失败。

处理方向不是把错误压掉,而是先确认这个文件到底是用什么编码保存的。可以回到生成这个文件的程序或编辑器里查看它的保存编码设置,再用一致的编码去读。

如果文件是你自己用 write_text 写的,就检查写入时有没有写 encoding,写的是什么。写入和读取用同一个编码,是避免这类报错最直接的办法。

为什么不用errors=ignore:它会让数据悄悄消失

read_text 有一个 errors 参数,含义与 open() 相同。errors="ignore" 的效果是遇到无法解码的字节就跳过,不报错。

它看起来能让程序“顺利跑完”,但代价是:那些跳过的字节对应的字符从结果里消失了,你拿到的字符串已经不完整,而且不会有任何提示。对文本处理来说,这等于把数据问题藏起来。

所以本文的做法是:不用 errors="ignore" 去掩盖编码问题,而是把编码确认清楚。遇到 UnicodeDecodeError,先查文件实际编码,再决定用什么编码读。

如果确实需要容错,也应先明确知道自己在丢弃什么,而不是默认把错误静默掉。本文不展开其他 errors 取值的具体行为。

读完之后怎么核对:把输入和输出对一遍

读出来之后,建议做一次简单核对,确认读到的内容和你写进去的一致。

核对方法(以下为编辑建议):

1. 比较行数。写入时用了几个换行,读回来的字符串按换行拆分后应该对应。

2. 比较首尾字符。看开头和结尾有没有多出或缺少字符。

3. 看有没有出现意料之外的替换字符或问号,这通常提示编码环节有问题。

from pathlib import Path

text = Path("exercise/notes_utf8.txt").read_text(encoding="utf-8")
print(len(text.splitlines()))
print(repr(text[:20]))

repr 能把不可见字符显示出来,方便你判断换行、空格是不是和预期一致。这一步只读文件,不修改它。

适用范围:本文只讲用 read_text 读取自建 UTF-8 文本文件、显式指定 encoding,以及文件不存在和编码不匹配两类报错的排查。不涉及写入其他格式、不涉及网络文件,也不涉及二进制文件的处理。

观看知识要点视频 18 秒

18秒无旁白要点导览,文字来自已审核正文;完整步骤、条件及参考资料见下方。

参考资料

以下原始资料提供本文依据;请结合日期、适用条件和产品说明查阅。

请结合原始资料的适用条件阅读。

返回文件整理 →