将数据文件与PyInstaller绑定(--onefile)

2024-05-21 11:39:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试用PyInstaller构建一个一个文件EXE,它将包含一个图像和一个图标。我一辈子都不能让它和--onefile一起工作。

如果我这样做的话,一切都很好。 当我使用--onefile时,它找不到引用的附加文件(在运行编译的EXE时)。它发现DLLs和其他一切都很好,只是没有两个图像。

我查看了运行EXE时生成的temp目录(例如,\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更新,将较新的答案标记为正确。


Tags: 文件图像src目录appdatagifexe
3条回答

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"

在应用程序未PyInstalled(即未设置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)

较新版本的PyInstaller不再设置env变量,因此Shish优秀的answer将不起作用。现在路径设置为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)

相关问题 更多 >