使用PyInstaller (--onefile) 打包数据文件
我正在尝试用PyInstaller制作一个单文件的EXE文件,里面要包含一张图片和一个图标。但是我怎么也搞不定这个--onefile
选项。
如果我使用--onedir
,一切都运行得很好。可是一用--onefile
,编译出来的EXE在运行时就找不到那些额外的文件。它能找到DLL和其他所有东西,就是找不到那两张图片。
我查看了运行EXE时生成的临时目录(比如\Temp\_MEI95642\
),发现文件确实在里面。当我把EXE放到那个临时目录里时,它就能找到这些文件。这让我很困惑。
这是我在.spec
文件中添加的内容
a.datas += [('images/icon.ico', 'D:\\[workspace]\\App\\src\\images\\icon.ico', 'DATA'),
('images/loaderani.gif','D:\\[workspace]\\App\\src\\images\\loaderani.gif','DATA')]
我还要补充一下,我也试过不把它们放在子文件夹里,但没有什么区别。
编辑: 由于PyInstaller更新,我把较新的答案标记为正确。
16 个回答
56
其他所有的回答都在说,如果你的应用程序没有被打包成可执行文件(也就是sys._MEIPASS
没有设置),那么就使用当前工作目录。这样做是不对的,因为它会限制你只能在脚本所在的目录运行你的应用程序。
一个更好的解决办法是:
import sys
import os
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base_path, relative_path)
65
pyinstaller会把你的数据解压到一个临时文件夹里,并把这个文件夹的路径存储在一个叫_MEIPASS2
的环境变量中。为了在打包模式下获取_MEIPASS2
目录,并在解压(开发)模式下使用本地目录,我使用了以下代码:
def resource_path(relative):
return os.path.join(
os.environ.get(
"_MEIPASS2",
os.path.abspath(".")
),
relative
)
输出结果:
# in development
>>> resource_path("app_icon.ico")
"/home/shish/src/my_app/app_icon.ico"
# in production
>>> resource_path("app_icon.ico")
"/tmp/_MEI34121/app_icon.ico"
252
新版本的PyInstaller不再设置env
变量了,所以Shish的那个很棒的回答就不适用了。现在路径是通过sys._MEIPASS
来设置的:
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)