Pyinstaller将外部数据文件打包到可执行文件中(onefolder or onefile)教程

前言

有时候我们想要发布写好的代码,使用Pyinstaller进行打包,但是我们程序有很多需要读取的外部数据,比如深度神经网络读取网络参数做预测。因为Pyinstaller打包有两种形式onefile或者onefolder。下面分别介绍。

环境:

ubuntu 16.04
pyinstaller : 3.3.1
python : 3.5.2

案例

test.py与text.txt放在同一个目录底下

file = 'text.txt'
with open(file, 'r') as f:
    while True:
        line = f.readline()     # 逐行读取
        if not line:
            break
        print(line)

onefolder

生成spec文件:

pyi-makespec test.py 

修改test.spec:

# -*- mode: python -*-

block_cipher = None
a = Analysis(['test.py'],
             pathex=['/home/lixin/test'],
             binaries=[],
             datas=[],  ### <-------hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='test',
          debug=False,
          strip=False,
          upx=True,
          runtime_tmpdir=None,
          console=True )

改为:

block_cipher = None
a = Analysis(['test.py'],
             pathex=['/home/lixin/test'],
             binaries=[],
             datas=[('test.txt','.')], ## <---- 修改此处添加外部文件
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='test',
          debug=False,
          strip=False,
          upx=True,
          runtime_tmpdir=None,
          console=True )

打包:

pyinstaller test.spec

此时生成两个文件夹,build以及dist,dist中的test文件夹即为发布的文件夹,可以看到,

test.txt被copy到了里面与可执行文件是同目录,完成!


onefile

其他操作跟onefolder相同,在生成s p e c时加上参数 -F
即:

pyi-makespec -F test.py

打包完成后,此时 dist下只有一个可执行文件,运行这个可执行文件,出现错误,找不到 ‘test.txt’ !!
原因:

运行可执行文件时,会先将可执行文件进行压缩,压缩的位置在 /tmp 下,再执行,所以被打包进去的数据文件在被解压的路径下,而,程序是在运行的路径下搜索,即可执行文件的目录下,所以找不到数据文件

添加如下代码:

import os 
import sys
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)

获取到pyinstaller临时文件夹的位置,再此位置进行文件搜索,即test.py文件修改如下:

import os 
import sys
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)

file = 'text.txt'
print(resource_path(file))  ## <----- 打印一下看看是否在临时文件夹下搜索
with open(resource_path(file), 'r') as f:
    while True:
        line = f.readline()     # 逐行读取
        if not line:
            break
        print(line)

重复以上步骤,在dist中运行可执行文件,得到如下结果:
(/tmp/_MEIY5Vljn/ 为我的pyinstaller临时文件夹)

/tmp/_MEIY5Vljn/test.txt

完美~


参考:
1. https://stackoverflow.com/questions/7674790/bundling-data-files-with-pyinstaller-onefile
2. https://pythonhosted.org/PyInstaller/usage.html#options

你可能感兴趣的:(tools)