Python 读取资源文件的正确方式:从相对路径陷阱到 importlib.resources
本文详解 Python 中读取资源文件的常见误区与最佳实践。直接运行脚本时相对路径有效,但在包(package)内部调用时易因工作目录不同导致 FileNotFoundError。文章对比了基于 os.path 的笨拙解法与 Python 3.7+ 推荐的 importlib.resources 模块,并深入解析如何处理嵌套子目录中的资源文件,确保打包部署时资源文件能被正确识别。
直接运行脚本时的文件读取
在 Python 开发中,若资源文件与当前执行的 .py 脚本位于同一目录,通常可直接通过文件名进行读取。例如:
with open('test.txt') as f:
content = f.read()
print('文件中的内容为:', content)
运行效果如下图所示:

包内调用时的路径陷阱
然而,上述方法仅适用于直接运行脚本的场景。当资源文件被封装在 Python 包(package)内部,且通过外部模块调用该包内的 .py 文件时,直接读取文件名往往会失败。我们来验证这一情况:

此时 Python 解释器将无法定位文件。原因在于,入口脚本 main.py 位于 ~/get_title 目录下,而目标资源文件 test.txt 实际存放在 ~/get_title/util 子目录中。由于执行的是 main.py,Python 默认在当前工作目录(即 ~/get_title)下查找 test.txt,因此无法找到位于子目录中的文件。
对于包内其他 Python 模块的引用,可以使用相对路径,例如通过 from .sql_util import conn 导入同一包下的 conn 对象。但需要注意的是,资源文件不能直接通过相对路径读取,具体表现如下:

基于 os.path 的路径拼接方案
一种可行的替代方案是获取当前执行代码所在的目录路径,并手动拼接资源文件的绝对路径。修改 read.py 文件如下:
import os
def read_file():
current_folder = os.path.dirname(__file__)
resource_path = os.path.join(current_folder, 'test.txt')
with open(resource_path) as f:
content = f.read()
print('文件中的内容为:', content)
运行效果如下图所示:

尽管该方法可行,但代码编写较为繁琐。
Python 3.7+ 推荐方案:importlib.resources
若你的 Python 环境版本不低于 3.7,推荐使用 importlib.resources 模块来高效读取资源文件:
from importlib import resources
with resources.open_text('包名', '资源路径') as f:
content = f.read()
运行效果如下图所示:

若需读取非文本类型的资源文件,可将 resources.open_text 替换为 resources.open_binary,以支持二进制文件的读取。
需特别注意,使用此方法时资源文件必须位于包的根目录下才能被正确识别。若资源文件存放在包内部的子目录中,importlib.resources 无法直接访问该子目录下的文件。
处理嵌套子目录中的资源文件
例如,假设包名为 util,其内部包含一个名为 deep_folder 的子文件夹,且资源文件 test.txt 位于 deep_folder 中。此时,若要读取该文件,必须在 deep_folder 目录下创建 __init__.py 文件,使其成为一个独立的子包。随后修改 read.py 的代码:
from importlib import resources
from . import deep_folder
def read_file():
with resources.open_text(deep_folder, 'test.txt') as f:
content = f.read()
print('文件中的内容为:', content)
将 deep_folder 作为模块导入,并将其作为 resources.open_text 的第一个参数传入,即可正确读取资源文件,效果如下:

以上内容涵盖了 Python 读取资源文件的核心要点,希望能为各位开发者提供实用参考,欢迎继续支持本站获取更多信息。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













