pyinstaller程序打包,资源嵌入exe

参考:https://blog.csdn.net/qq_48979387/article/details/132359366

一、参数说明

  1. -F 最终打包为一个可执行文件。
  2. -w 取消Windows显示窗口
  3. -add-data ‘dll;dll’,将当前目录dll下的文件打包到可执行文件的dll中,最终会在解压文件的dll文件下。

最终命令为:

pyinstaller.exe  -F -w --add-data 'dll/;dll/' --add-data 'ico/;ico/' .\xxx.py

二、资源嵌入exe

经常需要复制文件夹不仅麻烦,而且还无法防止里面的内容被用户修改。此时,我们可以使用pyinstaller的–add-data参数,将assets文件夹里面的资源嵌入到exe文件中。

资源嵌入exe只在单文件模式下使用。文件夹模式下,资源文件夹不会嵌入到exe中,但是会被复制到exe所在的文件夹。

使用资源嵌入后,资源文件夹的路径发生了变化,我们不能使用一般的相对路径来调用assets这样的内嵌资源文件夹。

pyinstaller单文件模式下的exe启动后,会将嵌入的资源文件放到一个临时的文件夹中,这个文件夹的名字不是固定的,叫做_MEIxxxxx,其中xxxxx是随机数。这个文件夹的路径在打包后会被放到sys._MEIPASS这个变量里面,只需要调用sys._MEIPASS就可以获得这个路径文件夹。

于是,我们通过以下函数返回正确的路径:

def get_path(relative_path):
    try:
        base_path = sys._MEIPASS # pyinstaller打包后的路径
    except AttributeError:
        base_path = os.path.abspath(".") # 当前工作目录的路径
 
    return os.path.normpath(os.path.join(base_path, relative_path)) # 返回实际路径

这个函数通过一个相对的路径返回实际的绝对路径。

需要注意:sys._MEIPASS这个属性只有在打包成exe后才被创建,以py代码执行的时候这个属性是不存在的,所以要通过try…except…代码块捕获异常。如果不是pyinstaller模式,那么就使用py文件所在的文件夹的路径作为基本路径。我们不必担心这个函数的工作原理,这个函数可以直接拿来用(是一位叫做davidpendergast的大佬写的)。

于是,我们将代码改成这样(省略了部分内容):

...
 
import sys
import os
 
def get_path(relative_path):
    try:
        base_path = sys._MEIPASS
    except AttributeError:
        base_path = os.path.abspath(".")
 
    return os.path.normpath(os.path.join(base_path, relative_path))
 
...
 
image = tk.PhotoImage(file=get_path("assets/image.gif"))
...

接下来进行打包:

pyinstaller -w -F --add-data assets;assets my_app_name.py

打包完成后会生成一个包含嵌入资源的单独的exe,无需将资源文件放到同一文件夹下也能正常运行。

–add-data的参数由源文件名src和目标文件名dest组成。路径的源文件名和目标文件名用文件分隔符进行分隔,源文件名是该文件或文件夹的原本的路径,目标文件名是该文件夹嵌入到exe后的放入的文件夹名。

文件分隔符:在Windows系统上是分号,大部分unix系统上是冒号,可以通过os.pathsep来查看当前系统上的文件分隔符。例如:

import os
os.pathsep
‘;’

比如–add-data "assets;assets"就表示将原本assets里面的所有文件,放入打包后的assets文件夹。再比如–add-data "assets/*.mp3;music"表示将原本assets里面的所有mp3文件,放入打包后的music文件夹。

当你遇到PyInstaller无法将资源文件(如图片、配置文件等)打包到生成的可执行文件中时,这通常是因为 PyInstaller 没有正确找到并包含这些外部依赖项。 为了确保资源文件能被打包进去,你可以按照以下步骤操作: ### 步骤一:修改 `.spec` 文件 1. **创建 spec 文件** 首先运行 `pyinstaller script.py` 来让 PyInstaller 自动生成一个 `.spec` 文件。 2. **编辑 .spec 文件** 打开生成的 `.spec` 文件,在其中添加你需要引入的静态资源路径。例如,如果你有一个名为 `data/images/icon.png` 的图像文件需要加入,则可以这样做: ```python a = Analysis( ['script.py'], datas=[('data/images', 'images')], # 将 data/images 目录下的所有内容复制到 images/ ) ``` 3. **再次构建项目** 使用命令行工具指定这个新的 `.spec` 文件进行打包: ``` pyinstaller your_script.spec ``` ### 步骤二:通过命令行参数直接设置数据 你也可以不需要手动调整 `.spec` 文件,而是利用 `-add-data` 参数在命令行里指明额外的数据目录: 对于 Windows 用户来说, ```bash pyinstaller -F --add-data "path/to/resource;resource" my_program.py ``` 注意这里的分隔符是英文状态下的`;`. 而对于 Mac 或 Linux 系统则使用冒号作为分隔符, ```bash pyinstaller -F --add-data "path/to/resource:resource" my_program.py ``` ### 获取内置资源的方法 假设你在程序中有这样的相对引用: Python 3.x 版本下推荐的方式是从 `pkg_resources` 库读取内部资源, ```python import pkg_resources image_path = pkg_resources.resource_filename("your_package_name", "relative/path/to/image.png") # or for binary files (recommended) image_data = pkg_resources.resource_string(__name__, "relative/path/to/file.bin") ``` 或者更简单地使用 sys._MEIPASS 属性, 当你的应用程序以冻结模式(frozen mode) 运行即通过 PyInstaller 创建出来的 EXE 文件启动时,sys._MEIPASS 变量会被自动设定为临时解压出的所有已嵌入资源的位置;而在非冻结环境下它会返回空字符串 "" ,因此建议按此条件分支处理: ```python if getattr(sys, 'frozen', False): resource_path = os.path.join(sys._MEIPASS, "relative/path/to/image.png") else: resource_path = "relative/path/from/project/root" ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值