arb*_*ark 88 python pyinstaller
我正在尝试使用PyInstaller构建一个单文件EXE,它包含一个图像和一个图标.我无法为我的生活而努力--onefile
.
如果我这样做--onedir
,一切工作都很顺利.当我使用时--onefile
,它找不到引用的附加文件(运行编译的EXE时).它找到了DLL和其他一切都很好,只是不是两个图像.
我查看了运行EXE时生成的temp-dir(\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')]
Run Code Online (Sandbox Code Playgroud)
我应该补充一点,我也试过不把它们放在子文件夹中,没有什么区别.
编辑: 由于PyInstaller更新,标记的较新答案正确.
小智 125
较新版本的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)
Run Code Online (Sandbox Code Playgroud)
Shi*_*ish 50
pyinstaller将您的数据解压缩到临时文件夹中,并将此目录路径存储在_MEIPASS2
环境变量中.要_MEIPASS2
以打包模式获取目录并在解压缩(开发)模式下使用本地目录,我使用:
def resource_path(relative):
return os.path.join(
os.environ.get(
"_MEIPASS2",
os.path.abspath(".")
),
relative
)
Run Code Online (Sandbox Code Playgroud)
输出:
# 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"
Run Code Online (Sandbox Code Playgroud)
Jon*_*art 18
在应用程序不是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)
Run Code Online (Sandbox Code Playgroud)
小智 11
使用Max的出色答案和这篇关于添加额外数据文件(如图像或声音)的文章以及我自己的研究/测试,我已经找到了我认为添加此类文件的最简单方法。
如果您想查看实际示例,我的存储库位于GitHub上。
注意:这是为了使用pyinstaller 的--onefile
或-F
命令进行编译。
为了解决这个问题,我们需要明确告诉 Pyinstaller 我们有额外的文件需要与应用程序“捆绑”。
我们还需要使用“相对”路径,以便应用程序在作为 Python 脚本或 Frozen EXE 运行时可以正常运行。
话虽如此,我们需要一个允许我们拥有相对路径的函数。使用Max Posted的函数我们可以轻松解决相对路径问题。
def img_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)
Run Code Online (Sandbox Code Playgroud)
我们将像这样使用上面的函数,以便当应用程序作为脚本或 Frozen EXE 运行时应用程序图标会显示。
icon_path = img_resource_path("app/img/app_icon.ico")
root.wm_iconbitmap(icon_path)
Run Code Online (Sandbox Code Playgroud)
下一步是我们需要指示 Pyinstaller 在编译时在哪里找到额外的文件,以便当应用程序运行时,它们会在临时目录中创建。
我们可以通过文档中所示的两种方式解决此问题,但我个人更喜欢管理自己的 .spec 文件,因此我们将这样做。
首先,您必须已经有一个 .spec 文件。就我而言,我能够通过使用额外参数运行来创建我需要的内容,您可以在此处pyinstaller
找到额外参数。因此,我的规范文件可能与您的略有不同,但在解释重要部分后,我将发布所有内容以供参考。
added_files本质上是一个包含元组的列表,在我的例子中,我只想添加一个图像,但您可以使用添加多个 ico、png 或 jpg('app/img/*.ico', 'app/img')
您也可以像这样创建另一个元组以added_files = [ (), (), ()]
具有多个导入
元组的第一部分定义您想要添加什么文件或什么类型的文件以及在哪里可以找到它们。将此视为 CTRL+C
元组的第二部分告诉 Pyinstaller 创建路径“app/img/”并将文件放置在该目录中,该目录与运行 .exe 时创建的任何临时目录相关。将此视为 CTRL+V
在 下a = Analysis([main...
,我已经设置了datas=added_files
,最初它曾经是datas=[]
,但我们希望导入导入列表,所以我们传入自定义导入。
除非您想要 EXE 的特定图标,否则您不需要这样做,在规范文件的底部,我告诉 Pyinstaller 使用选项设置 exe 的应用程序图标icon='app\\img\\app_icon.ico'
。
added_files = [
('app/img/app_icon.ico','app/img/')
]
a = Analysis(['main.py'],
pathex=['D:\\Github Repos\\Processes-Killer\\Process Killer'],
binaries=[],
datas=added_files,
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='Process Killer',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True , uac_admin=True, icon='app\\img\\app_icon.ico')
Run Code Online (Sandbox Code Playgroud)
我很懒;我不喜欢输入不必要的东西。我创建了一个 .bat 文件,只需单击即可。您不必这样做,即使没有它,此代码也可以在命令提示符 shell 中正常运行。
由于 .spec 文件包含我们所有的编译设置和参数(也称为选项),我们只需将该 .spec 文件提供给 Pyinstaller 即可。
pyinstaller.exe "Process Killer.spec"
Run Code Online (Sandbox Code Playgroud)
dil*_*ten 10
也许我错过了一步或做错了什么,但上面的方法,没有将数据文件与PyInstaller捆绑到一个exe文件中.让我分享我所做的步骤.
步骤:使用导入sys和os模块将上述方法之一写入py文件.我试过了他们两个.最后一个是:
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)
Run Code Online (Sandbox Code Playgroud)步骤:将pyi-makespec file.py写入控制台,以创建file.spec文件.
步骤:使用Notepad ++打开file.spec,添加如下数据文件:
a = Analysis(['C:\\Users\\TCK\\Desktop\\Projeler\\Converter-GUI.py'],
pathex=['C:\\Users\\TCK\\Desktop\\Projeler'],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
#Add the file like the below example
a.datas += [('Converter-GUI.ico', 'C:\\Users\\TCK\\Desktop\\Projeler\\Converter-GUI.ico', 'DATA')]
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
exclude_binaries=True,
name='Converter-GUI',
debug=False,
strip=False,
upx=True,
#Turn the console option False if you don't want to see the console while executing the program.
console=False,
#Add an icon to the program.
icon='C:\\Users\\TCK\\Desktop\\Projeler\\Converter-GUI.ico')
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
strip=False,
upx=True,
name='Converter-GUI')
Run Code Online (Sandbox Code Playgroud)步骤:我按照上面的步骤,然后保存spec文件.最后打开控制台并编写了pyinstaller file.spec(在我的例子中,file = Converter-GUI).
结论:dist文件夹中仍有多个文件.
注意:我使用的是Python 3.5.
编辑:最后它与Jonathan Reinhart的方法一起使用.
步骤:使用导入sys和os将以下代码添加到python文件中.
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)
Run Code Online (Sandbox Code Playgroud)步骤:通过添加文件路径调用上述函数:
image_path = resource_path("Converter-GUI.ico")
Run Code Online (Sandbox Code Playgroud)步骤:将调用函数的上述变量写入代码所需路径的位置.在我的情况下它是:
self.window.iconbitmap(image_path)
Run Code Online (Sandbox Code Playgroud)步骤:在python文件的同一目录中打开控制台,编写如下代码:
pyinstaller --onefile your_file.py
Run Code Online (Sandbox Code Playgroud)步骤:保存并退出路径文件.转到包含spec和py文件的文件夹.再次打开控制台窗口并键入以下命令:
pyinstaller your_file.spec
Run Code Online (Sandbox Code Playgroud)在6.步骤之后,您的一个文件就可以使用了.
而不是按照建议重写我的所有路径代码,我更改了工作目录:
if getattr(sys, 'frozen', False):
os.chdir(sys._MEIPASS)
Run Code Online (Sandbox Code Playgroud)
只需在代码的开头添加这两行,就可以保留原样.
我一直在处理这个问题很长一段时间(好吧,很长时间)。我几乎搜索了所有来源,但事情并没有在我脑海中形成模式。
最后,我想我已经找到了要遵循的确切步骤,我想分享一下。
请注意,我的回答使用了其他人对此问题的回答的信息。
假设我们有一个project_folder,文件树如下:
Run Code Online (Sandbox Code Playgroud)project_folder/ main.py xxx.py # another module yyy.py # another module sound/ # directory containing the sound files img/ # directory containing the image files venv/ # if using a venv
首先,假设您已将路径sound/
和img/
文件夹定义为变量sound_dir
,img_dir
如下所示:
img_dir = os.path.join(os.path.dirname(__file__), "img")
sound_dir = os.path.join(os.path.dirname(__file__), "sound")
Run Code Online (Sandbox Code Playgroud)
您必须更改它们,如下所示:
img_dir = resource_path("img")
sound_dir = resource_path("sound")
Run Code Online (Sandbox Code Playgroud)
其中,resource_path()
在脚本顶部定义为:
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)
Run Code Online (Sandbox Code Playgroud)
如果使用 venv,则激活虚拟 env,
如果您还没有安装 pyinstaller,请通过:pip3 install pyinstaller
。
运行:pyi-makespec --onefile main.py
为编译和构建过程创建规范文件。
这会将文件层次结构更改为:
Run Code Online (Sandbox Code Playgroud)project_folder/ main.py xxx.py # modules xxx.py # modules sound/ # directory containing the sound files img/ # directory containing the image files venv/ # if using a venv main.spec
打开(带编辑器)main.spec
:
在它的顶部,插入:
added_files = [
("sound", "sound"),
("img", "img")
]
Run Code Online (Sandbox Code Playgroud)
然后,将行更改datas=[],
为datas=added_files,
有关在此处完成的操作的详细信息,main.spec
请参见此处。
跑 pyinstaller --onefile main.spec
而这一切,你可以运行main
在project_folder/dist
任何地方,而无需其文件夹中的任何东西。您只能分发该main
文件。现在,一个真正的独立.
归档时间: |
|
查看次数: |
83881 次 |
最近记录: |