使用pyinstaller构建图片及一些配置文件如txt和xml文件

9 投票
2 回答
3324 浏览
提问于 2025-04-17 10:17

我在使用pyinstaller的时候遇到了一些麻烦,主要是想把一些数据文件,比如图片和文本文件,添加到我的Python程序里。举个例子,我创建了一个工具栏,上面有图标,这些图标我放在一个叫做images的单独文件夹里。此外,我还有一些文本和XML文件,用来存储一些配置,这些文件放在另一个叫做data_files的文件夹里。所有的Python文件则放在一个叫做source的文件夹里。

当我尝试用pyinstaller来构建这个Python程序时,pyinstaller能够成功构建source文件夹里的所有内容,但images和data_files文件夹里的内容却无法构建。我查看了pyinstaller的文档,但没有找到解决办法。我在网上搜索了很多,找到的只有这个资源,但感觉这个资源并不够全面。

我主要想问的是:如何使用pyinstaller构建一个exe文件,同时包含像images和配置文件这样的单独文件夹呢?

编辑:我找到了解决办法。当你创建spec文件时,需要在a.datas参数中添加相关内容。

# -*- mode: python -*-
a = Analysis([os.path.join(HOMEPATH,'support/_mountzlib.py'), os.path.join(HOMEPATH,'support/useUnicode.py'), '/home/vmode/Desktop/derlem2/sources/TextSTAT.py'],
             pathex=['/home/pyinstaller'])
a.datas += [("Images/New.gif","/home/vmode/Desktop/derlem2/Images/New.gif","DATA")]
a.datas += [("Images/Open.gif","/home/vmode/Desktop/derlem2/Images/Open.gif","DATA")]
a.datas += [("Images/Column.gif","/home/vmode/Desktop/derlem2/Images/Column.gif","DATA")]
pyz = PYZ(a.pure)
exe = EXE( pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name=os.path.join('dist', 'TextSTAT'),
          debug=False,
          strip=False,
          upx=True,
          console=1 )

上面的spec代码是为我的项目设计的。从这段代码可以看到,我包含了3个图标,以便和Python程序一起构建。当程序生成后,会有一个独立的可执行文件,并且这些图标会嵌入其中。

但是如果我们有很多文件呢?假设我们有1000个图标要在程序中使用,那手动写到spec文件里就太麻烦了。应该有一个循环系统来读取文件目录,并动态添加这些文件。但我找不到如何动态添加这些文件的方法。我觉得手动添加这么多文件是不现实的。如果有人知道,请分享一下。

2 个回答

1

如果所有的图片都放在同一个文件夹里,你可以使用树形结构来查看它们。

dict_tree = Tree('/home/vmode/Desktop/derlem2/Images', prefix = 'Images')
a.datas += dict_tree
5

在创建我的可执行文件时,我也遇到了这个问题。因为.spec文件是用Python写的,所以我用到了glob模块来解决这个问题。

imagesList = []
imagesList.append( ('icon.ico', '..\\pathfinder\\icon.ico',  'DATA') )
import glob
allImages = glob.glob('..\\pathfinder\\*.png')
for eachImage in allImages:
    imageParts = eachImage.split('\\')
    imagesList.append( (imageParts[-1], eachImage,  'DATA') )
print imagesList
a.datas += imagesList

第二行提到的icon.ico是单独处理的,因为它的文件扩展名不同,所以可以排除在外。'..\pathfinder'是我程序所有文件的路径(相对于pyinstaller目录)。glob会在这个目录下搜索所有的.png文件(我有65个,不想手动写出来),并返回一个包含这些文件的列表,列表里的每个项都是完整的相对路径。为了把这些路径分开成文件名的列表,我用字符串的split()方法按反斜杠分割。然后,对于每个文件名,我把分割后的最后一部分(也就是图片的文件名)和完整路径一起放到我自己创建的列表中,形成一个元组。最后,把所有文件的列表添加到a.datas中。

我通过命令行确认这个方法确实有效,而且你可以复制这个循环来处理其他文件扩展名。

不过,遗憾的是,尽管看起来文件名提取和附加都没问题,我的可执行文件还是没有包含这些文件(或者说可执行文件找不到它自己数据里的文件),我仍然需要把原始图片放在同一个目录下才能正常工作;可能是我元组里的元素顺序搞错了(如果是这样,你应该相应地调整我的代码)。希望这个动态加载的方法对你来说还是有效的。imageParts[-1]代表每个.png文件的文件名,而eachImage代表它的完整路径(如果在glob中使用的是相对路径的话)。

撰写回答