将配置文件添加到pyinstaller语言 - honefile exe文件之外,将其添加到DIST目录中



情况

我在Windows上使用Pyinstaller来制作我的项目的EXE文件。

我想使用--onefile选项具有干净的结果和易于分发文件/程序。

我的程序使用config.ini文件来存储配置选项。该文件可以由用户自定义。

问题

使用 --onefile选项,pyinstaller将所有声明为" data-file&quot s in the单个.exe文件中"。

我已经看到了此请求,但是它提供了在一个file 内添加捆绑文件的建筑物而不是外部,在.exe的相同级别和同一dist目录中。

在某个时候,我想使用shutil.copy命令.pecec ins.pec文件复制此文件...但是我认为是错误的。

我该如何解决此问题?

github上的存储库帮助我找到了我的问题的解决方案。

我已经使用了shutil模块和.spec文件来使用Pyinstaller --onefile选项添加额外的数据文件(在我的情况下,是config-sample.ini文件)。

为Pyinstaller制作.spec文件

首先,我创建了一个使用我需要的选项的MakePec文件:

pyi-makespec --onefile --windowed --name exefilename scriptname.py

此命令创建一个exefilename.spec文件,用于与Pyinstaller一起使用。

修改exefilename.spec,添加shutil.copyfile

现在我已经编辑了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软件包中可用的所有方法。

运行pyinstaller

最后一步是运行编译过程

pyinstaller --clean exefilename.spec

结果是,在DIST文件夹中,您应该将编译的.EXE文件与复制的数据文件一起使用。

考虑

在Pyinstaller的正式文档中,我找不到获得此结果的选项。我认为它可以被视为解决方法...

这是如何访问与输出文件相同级别的文件。诀窍是Sys.ecutable是单文件.EXE所在的位置。因此,简单地做到了:

import sys
import os.path
CWD = os.path.abspath(os.path.dirname(sys.executable))

使用它,例如用

with open(os.path.join(CWD, "config.ini")) as config_file:
    print(config_file.read())

os.getcwd()/相对路径不起作用的原因

可执行文件只是一个可执行的存档,在执行时提取到临时目录,在该目录中执行 .pyc 文件。因此,当您调用os.getcwd()而不是通往可执行文件的路径时,您可以获得通往临时文件夹的路径。

我的解决方案与Stefano-Giraldi的优秀人物相似解决方案。当将目录传递给shutil.copyfile时,我被拒绝了。

我最终使用shutil.copytree

import sys, os, shutil
site_packages = os.path.join(os.path.dirname(sys.executable), "Lib", "site-packages")
added_files = [
                (os.path.join(site_packages, 'dash_html_components'), 'dash_html_components'),
                (os.path.join(site_packages, 'dash_core_components'), 'dash_core_components'),
                (os.path.join(site_packages, 'plotly'), 'plotly'),
                (os.path.join(site_packages, 'scipy', '.libs', '*.dll'), '.')
                ]
working_dir_files = [
                ('assets', 'assets'),
                ('csv', 'csv')
                ]
print('ADDED FILES: (will show up in sys._MEIPASS)')
print(added_files)
print('Copying files to the dist folder')
print(os.getcwd())
for tup in working_dir_files:
        print(tup)
        to_path = os.path.join(DISTPATH, tup[1])
        if os.path.exists(to_path):
                if os.path.isdir(to_path):
                        shutil.rmtree(to_path)
                else:
                        os.remove(to_path)
        if os.path.isdir(tup[0]):
                shutil.copytree(tup[0], to_path)
        else:
                shutil.copyfile(tup[0], to_path)
#### ... The rest of the spec file
a = Analysis(['myapp.py'],
             pathex=['.', os.path.join(site_packages, 'scipy', '.libs')],
             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='myapp',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          upx_exclude=[],
          runtime_tmpdir=None,
          console=True)

这避免了_mei文件夹,并防止它复制您在DIST文件夹中而不是在临时文件夹中所需的配置文件。

我尝试过许多方法,这对我有用:

  1. 不要为配置文件使用 .py 扩展名。改用JSON。JSON不好,因为您不能在其中写评论,但是如果您想制作一个EXE文件,则不幸的是必须使用它。

  2. 在您的脚本中,加载以这种方式设置文件:

    filename = "settings.json"
    contents = open(filename).read()
    config = eval(contents)
    setting1 = config['setting1']
    
  3. 运行pyinstaller或auto-py-to-exe(我尝试过,所有作品)

  4. 将您的 settings.json 将您的 .exe .exe 文件的文件放在同一文件夹中。

  5. 运行它,它将从该文件中进行设置。

如果您的任何Python脚本都使用外部文件(JSON,TEXT或任何配置文件),并且您希望将这些文件包含在可执行文件中,请在a Windows 系统。

考虑到有一个Python脚本app.py并且它读取JSON文件config.json,我们的目标是将config.json文件添加到某个合适的目录中,该文件可以在应用程序运行时访问该文件(作为.exe)。P>

即使app.py未直接读取config.json,此答案也适用。config.json可以由app.py使用的任何模块读取,答案仍然会有所帮助。

app.py
config.json

步骤1:在应用程序运行时解决JSON文件的路径

应用程序正在运行时,将文件复制到Windows系统C:Users<You>AppDataLocalTempMEIxxx上的临时位置。因此,app.py需要从此临时位置读取JSON文件。但是,该应用在运行时如何知道它必须在哪个目录中搜索文件?从这个出色的答案中,在app.py中,我们将有一个功能

def resolve_path(path):
    if getattr(sys, "frozen", False):
        # If the 'frozen' flag is set, we are in bundled-app mode!
        resolved_path = os.path.abspath(os.path.join(sys._MEIPASS, path))
    else:
        # Normal development mode. Use os.getcwd() or __file__ as appropriate in your case...
        resolved_path = os.path.abspath(os.path.join(os.getcwd(), path))
    return resolved_path
# While reading the JSON file
with open(resolve_path("config.json"), "r") as jsonfile:
   # Access the contents here

现在app.py知道在哪里查找文件。在此之前,我们需要指示Pyinstaller将config.json复制到该临时文件目录中。

注意,您需要在python脚本中使用相对路径的任何地方使用resolve_path

步骤2:制作和编辑.spec文件以复制config.json

当我们希望创建app.py的可执行文件时,我们首先为其创建一个.spec文件(参考@stefano Giraldi的答案)

pyi-makespec --onefile --windowed --name appexe app.py

打开生成的appexe.spec文件,您会注意到这些内容,

# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
a = Analysis(
    ...
    datas=[],
    ...
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
    ...
)

创建一个新列表files并将其传递到datas参数,

# -*- mode: python ; coding: utf-8 -*-
block_cipher = None
files = [
    ( 'config.json' , '.' )
]
a = Analysis(
    ...
    datas=files,
    ...
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
    ...
)

元组('config.json', '.')表示文件的源和目标路径。目标路径相对于临时文件目录。

步骤3:构建可执行文件

最后,我们可以运行.spec文件来构建安装程序,

pyinstaller --clean appexe.spec

最终的安装程序现在应在没有任何FileNotFoundErrors。

i通过删除config file( config.py <<em> config.py 对我而言)从项目文件夹中运行Pyinstaller。

config_str = """
some configuration code string
"""
with open('path_to_somewhere\config.ini', 'w', encoding="gbk") as writer:
    writer.write(config_str)

相关内容

  • 没有找到相关文章

最新更新