将配置文件添加到 PyInstaller --onefile EXE 文件之外,并将其放入 dist 目录中。
将配置文件添加到 PyInstaller --onefile EXE 文件之外,并将其放入 dist 目录中。
情况
我在Windows上使用PyInstaller制作一个项目的EXE文件。
我想使用--onefile
选项以获得一个干净的结果和一个易于分发的文件/程序。
我的程序使用一个config.ini
文件来存储配置选项。这个文件可以由用户自定义。
问题
使用--onefile
选项,PyInstaller将所有声明的"data-file"放在单个的.exe
文件中。
我看到了这个请求,但它给出的指令是将一个捆绑文件放在onefile内部而不是在外部,与.exe
文件处于同一级别,并位于同一个dist
目录中。
我曾经考虑在.spec文件中使用shutil.copy命令来复制这个文件...但我觉得我走错了路。
我该如何解决这个问题?
问题的原因是在使用shutil.copyfile
函数将目录传递给shutil.copyfile
时出现了权限被拒绝的错误。为了解决这个问题,使用shutil.copytree
函数来代替shutil.copyfile
函数。具体解决方法如下:
首先,定义了两个列表:added_files和working_dir_files,分别存储要复制的文件和目录的路径。
然后,使用os.getcwd()
函数获取当前工作目录,并通过os.path.join()
函数将目标路径和要复制的文件或目录的名称连接起来。如果目标路径已经存在,则使用shutil.rmtree()
函数删除该路径。如果目标路径是一个目录,则使用shutil.copytree()
函数将源目录复制到目标路径。如果目标路径是一个文件,则使用shutil.copyfile()
函数将源文件复制到目标路径。
最后,使用Analysis()
函数和EXE()
函数创建可执行文件。
通过这种方法,可以避免_MEI文件夹的出现,并且可以将配置文件复制到dist文件夹中而不是临时文件夹中。
问题出现的原因:在使用PyInstaller的--onefile选项将配置文件添加到dist文件夹时,没有提供一种官方文档中没有提到的直接方法。
解决方法:根据一个GitHub上的存储库的帮助,可以通过使用shutil模块和.spec文件来实现此目的。具体步骤如下:
1. 创建一个.spec文件:使用以下命令创建一个makespec文件,其中包含所需的选项:
pyi-makespec --onefile --windowed --name exefilename scriptname.py
该命令将创建一个exefilename.spec文件,用于与PyInstaller一起使用。
2. 修改exefilename.spec文件:在exefilename.spec文件的末尾添加以下代码:
import shutil shutil.copyfile('config-sample.ini', '{0}/config-sample.ini'.format(DISTPATH)) shutil.copyfile('whateveryouwant.ext', '{0}/whateveryouwant.ext'.format(DISTPATH))
这段代码将在编译过程的末尾复制所需的数据文件。可以使用shutil模块中可用的所有方法。
3. 运行PyInstaller:运行编译过程的最后一步:
pyinstaller --clean exefilename.spec
结果是,在dist文件夹中,应该有编译后的.exe文件以及复制的数据文件。
这种方法可以被视为一种解决方法,虽然官方PyInstaller文档中没有提供直接的选项来获得这种结果。
注意:这是一个旧的答案,但我仍在寻找解决这个问题的方法。这个答案得到了很多赞,所以我认为我可能遗漏了一些东西。这段代码将配置文件复制到与可执行文件相同的目录,但似乎没有办法在运行时向可执行文件提供配置文件的路径。这个问题在这个答案中得到了解决,但没有解决将文件复制到onefile可执行文件所在目录的问题。
另外,还有一个相关的问题,即如何将Excel文件从临时文件夹移动到实际的exe文件夹。可以在这个链接中找到解答:stackoverflow.com/questions/74172706/…
问题的原因是在使用 PyInstaller 打包成仅包含一个可执行文件的 .exe 文件时,无法通过 os.getcwd() 或相对路径访问与输出文件位于同一级别的文件。原因是可执行文件是一个执行时被解压到临时目录并执行其中的 .pyc 文件的可执行存档文件。
为了解决这个问题,可以使用 sys.executable 获取到可执行文件的路径,并通过该路径获取到当前工作目录(CWD)。具体代码如下:
import sys import os.path CWD = os.path.abspath(os.path.dirname(sys.executable))
然后,可以使用 os.path.join() 方法将文件名与当前工作目录拼接,从而获取到需要访问的文件的路径。例如:
with open(os.path.join(CWD, "config.ini")) as config_file: print(config_file.read())
通过以上代码,就可以成功地访问到与输出文件位于同一级别的配置文件(config.ini)的内容。这样就解决了无法通过 os.getcwd() 或相对路径访问文件的问题。