3

我也是第一次尝试构建一个简单的 --onefile exe,其中包含数据文件,但是 Pyinstaller 在构建 .exe 时似乎没有找到它们。一个 --onedir 构建似乎工作正常。

此时我也在使用 --debug 开关。我能够运行 onefile 可执行文件,并且可以看到它似乎开始工作了。程序找到 (sys._MEIPASS) 临时目录正常(按指示打印所需的目录名称),但在从临时目录中查找第一个数据文件时报告“没有此类文件或目录”错误。我在 .exe 上使用了 archiveviewer.py 并没有在那里找到所需的数据文件——这似乎是问题所在,但我不知道为什么。构建的数据文件位于规范文件描述的目录中。我完整的规格文件是

# -*- mode: python -*-

a = Analysis(['develop6.py'],
         pathex=['C:\\PYINST20'],
         hiddenimports=[],
         hookspath=None)

a.datas += [ ('conlist.txt', 'C:\\pyinst20\\conlist.txt', 'DATA'), ('imageblank.gif', 'C:\\pyinst20\\imageblank.gif', 'DATA')]

pyz = PYZ(a.pure)

exe = EXE(pyz,
      a.scripts,
      a.binaries,
      a.zipfiles,
      a.datas,
      name=os.path.join('dist', 'develop6.exe'),
      debug=True,
      strip=None,
      upx=True,
      console=True )
4

5 回答 5

4

(这个问题很老,但它是我发现解决同一问题的唯一来源之一,我将在这里分享我的解决方案,以防它可以帮助某人)

在 --onefile 模式下将数据文件添加到脚本中需要做两件事。

1.调整路径

在您的脚本中,调整您的路径以在包中查找数据文件。根据此处的 PyInstaller 文档,可执行文件是从临时文件启动的,因此您的路径必须处理此动态部分:

对于具有以下相对路径的文件:./your/file/is/here.ext

代码将是:

import sys
wd = sys._MEIPASS
file_path = os.path.join(wd,<your>,<file>,<is>,<here>)

注意:要使您的代码也适用于其他上下文,您可以执行以下操作:

import sys
import os
try:
   wd = sys._MEIPASS
except AttributeError:
   wd = os.getcwd()
file_path = os.path.join(wd,<your>,<file>,<is>,<here>)

2. 在 PyInstaller 规范中添加数据文件路径

根据此处的 PyInstaller 文档,有两种方法可以将数据文件添加到包中:

  1. 从脚本目录--add-files运行时将选项和文件作为参数传递pyinstaller <yourscript.py>

  2. 首先通过导航到您的脚本目录并运行来生成一个规范文件pyi-makespec <yourscript.py>,然后将您的文件添加到元组列表中data=[]。元组包含文件的实际路径和包中的路径。如果您遵循第一点,这应该看起来像 datas = [('/your/file/is/here.ext','/your/file/is/')]

然后PyInstall <yourscript.spec>根据您的规范文件运行以构建捆绑包。

于 2019-01-17T04:51:43.590 回答
1

使用像 AutoPyToExe 这样的应用程序可以解决您在使用 PyInstaller 时遇到的大部分挑战。该界面允许您解决您在此处列出的大部分挑战。通过简单地选择文件的位置而不是移动它们,查看附件,了解如何隐藏文件、数据文件、干净构建等等。

在此处输入图像描述

于 2020-09-09T11:45:27.317 回答
1

令人困惑的堆栈溢出线程Pyinstaller文档之间来回走动之后,我终于能够捆绑我的应用程序。

一步步:

  1. 在您的应用程序根目录和. venv/bin/activated:

    ➜  ~ pip install pyinstaller
    ➜  ~ pyi-makespec --windowed --onedir --i ./resources/img/icn.icns \
          --osx-bundle-identifier "com.myname.macOS.myappname" app.py
    
  2. 现在,稍微修改app.spec一下:

    added_files = [
     ('resources/img', 'resources/img'),
     ( 'README.md', '.' )
     ]
    

    使用资源的相对路径初始化字典 added_files并设置datas = added_files. 在我的应用程序中,我使用了./resources/img相对于我的 main.py 文件的图像。

  3. 最后,这可能是最容易忘记的一步,而且不那么明显:

    ➜  ~ pyinstaller --onefile app.spec
    

请注意,这最后一步取自此处

于 2016-06-27T06:12:58.910 回答
0

我相信我发现了问题,它与规范文件的正文无关。使用规范文件运行 pyinstaller 时,我的命令行语法似乎错误。正常运行时:

pyinstaller.py [options] <my_specfile.spec>

似乎工作。

于 2013-01-13T23:43:26.613 回答
0

当脚本作为包运行时,我们可以按照文档设置不同的文件路径。但是,我的解决方法是建立一个稳定的顶级目录,所有非脚本文件都在其中,并与所有模块共享这个顶级目录。然后在每个模块中,我可以根据顶级目录创建文件路径。

例如,在此布局中,所有模块代码都位于src文件夹中。这些模块需要访问conf文件夹、database文件夹和otherconfig.yaml.

├── conf
│   └── config.ini
├── database
├── entry_point.py
├── otherconfig.yaml
├── root_path.py
└── src
    ├── pkg1
    └── pkg2

root_path.py看起来像这样:

import os

path = os.getcwd()

在每个模块中,我可以为配置文件创建文件路径,如下所示:

import root_path

config_path = f"{root_path.path}/conf/config.ini"
otherconfig_path = f"{root_path.path}/otherconfig.yaml"

然后,在通过创建单文件可执行文件后pyinstaller -F entry_point.py(不添加任何文件),我们只需要重新创建相同的布局,每个模块中的文件路径仍然可以工作。

├── bundled_executable
├── conf
│   └── config.ini
├── database
└── otherconfig.yaml

当然,这种变通办法不能隐藏配置文件。但是对于我的用例,我需要让用户自由修改配置文件,所以不隐藏文件实际上对我有用。

于 2019-10-31T01:17:02.277 回答