管理 pyz 应用程序中的资源

Manage resources in pyz applications

我有一个多模块 python 应用程序,我用 python3 -m zipapp.

打包在 pyz 可执行文件中

我想使用它需要的一些资源来部署此应用程序运行(一些文本文件)。我试图将这些文本文件添加到 project_root/res,然后只执行类似 with open("./res/resource1.txt", "r") as f: do_something() 的操作,但当然找不到文件。

如何读取嵌入在 zipapp 应用程序中的文本文件?

import pkgutil
pkgutil.get_data(<module name>, 'resource1.txt')

将return一个字节对象。

<module name> 应该是一个字符串,其中包含 resource1.txt 所在的文件夹的路径,就好像您正在尝试导入它一样;例如如果需要 /res/some_subfolder/foo.txt 那么你会 pkgutil.get_data('yourmodule.res.some_subfolder', 'foo.txt').

请注意,此实例中的 ressome_subfolder 必须在 Python 模块上完整,而不仅仅是目录(区别在于是否存在名为 __init__.py);否则 zipapp 将忽略它们。因此,上例中的文件夹结构必须是:

project root
 | main.py
 | <whatever other files you have>
 | res
 |  | __init__.py
 |  | some_subfolder
 |  |  | __init__.py
 |  |  | foo.txt

同样,如果你愿意,这些文件可以是空白的,它们必须存在(尽管如果你在其中放入代码,你可以执行 import res(或 import res.some_subfolder)并且它will 运行 res/__init__.py,如果您愿意的话,这可能是一种从一个地方组织所有资源的有用方法)。顺便说一下,如果阅读本文的任何人像大多数 Python 程序员一样不熟悉模块的工作原理,here 是来自 Python 文档的快速教程。


此外,如果您只是使用 zipapp(而不是使用 pyinstaller 创建的 exe),您可以简单地:

 import sys
 import zipfile
 
 with zipfile.ZipFile(sys.argv[0]) as zf:
      with zf.open('res/resource1.txt') as f:
           print(f.read())