登录
首页精彩阅读Pyinstaller打包,彻底解决图片、数据路径问题
Pyinstaller打包,彻底解决图片、数据路径问题
2022-03-04
收藏

作者:麦叔

来源:麦叔编程

Pyinstaller打包,解决图片、数据路径问题!

这是文件路径系列的第5篇。很多网友碰到找不到文件的问题,都是因为对Python读取文件路径的知识理解不深。本周的每天3分钟,我们就主要围绕路径问题。

如果要把Python打包成一个可执行文件,或者一个文件夹,最常用的方式是pyinstaller

使用方法很简单,但是很多麦友会碰到路径问题:如果代码中需要用到图片或数据文件,打包后执行会失败!

咱们今天就来解决这个问题。篇幅有限,我演示一个简单的例子,并指出解决更复杂的问题的方向。

案例介绍

本例子将要打包如下文件结构:

--058 --058.py --058.txt 

文件夹058下有两个文件:058.py和058.txt。其中058.py源代码如下:

import pathlib
folder = pathlib.Path(__file__).parent.resolve()
print(f'当前python文件所在目录:{folder}') with open(f'{folder}/058.txt') as file:
 print(file.read())

也就是说058.py文件需要用到058.txt文件。

直接运行,会打印出数据文件的内容:

当前python文件所在目录:/Users/maishu/git/wx_maishucode/code/058
跟麦叔搞定路径问题

我们的任务是:打包成一个exe文件,可以分发给没有Python,不懂Python的人使用。

以下例子用Mac做演示,在Windows或Linux下也是一样的。

安装pyinstaller

pyinstaller是一个Python的模块,我们先来安装它。

在命令行下运行:

python -m pip install pyinstaller

执行结果如下,安装成功:

maishu@msmacbook 058 % python -m pip install pyinstaller
Collecting pyinstaller
  Downloading pyinstaller-4.9-py3-none-macosx_10_13_universal2.whl (1.6 MB)
     |████████████████████████████████| 1.6 MB 152 kB/s 
Collecting pyinstaller-hooks-contrib>=2020.6 Downloading pyinstaller_hooks_contrib-2022.2-py2.py3-none-any.whl (223 kB)
     |████████████████████████████████| 223 kB 117 kB/s 
Collecting macholib>=1.8 Downloading macholib-1.15.2-py2.py3-none-any.whl (37 kB)
Requirement already satisfied: setuptools in /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages (from pyinstaller) (57.4.0)
Collecting altgraph
  Downloading altgraph-0.17.2-py2.py3-none-any.whl (21 kB)
Installing collected packages: altgraph, pyinstaller-hooks-contrib, macholib, pyinstaller
Successfully installed altgraph-0.17.2 macholib-1.15.2 pyinstaller-4.9 pyinstaller-hooks-contrib-2022.2 WARNING: You are using pip version 21.2.3; however, version 22.0.3 is available.
You should consider upgrading via the '/Library/Frameworks/Python.framework/Versions/3.10/bin/python3 -m pip install --upgrade pip' command. 

其中的WARNING无伤大雅,先不用管。

打包失败

现在我们来尝试打包。用pyinstaller的打包过程是很简单的。

去到058所在的文件夹,运行如下命令:

pyinstaller 058.py 

会发现058文件夹下多了很多内容:

Pyinstaller打包,彻底解决图片、数据路径问题

其中dist目录就是打包好的内容所在文件夹。dist是distribution的缩写,中文是发布的意思。

进去看看,会发现dist里面又有一个058文件夹,里面放着很多内容,包括了python解释器等。

Pyinstaller打包,彻底解决图片、数据路径问题

理论上,我们把整个058文件夹发给别人。

他们运行其中的058可执行文件(图中第一个),就可以正确执行我们的程序。

现在我去双击一下058文件,得到的结果是:

maishu@msmacbook ~ % /Users/maishu/git/wx_maishucode/code/058/dist/058/058 ; exit;
当前python文件所在目录:/Users/maishu/git/wx_maishucode/code/058/dist/058
Traceback (most recent call last): File "058.py", line 5, in <module>
FileNotFoundError: [Errno 2] No such file or directory: '/Users/maishu/git/wx_maishucode/code/058/dist/058/058.txt' [8404] Failed to execute script '058' due to unhandled exception!
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

运行失败了:FileNotFoundError,因为数据文件没有打包进去。

打包成功:--add-data选项

我们前面用了最简单的打包命令,它会把python程序打包进去,不会复制数据,当然会报错了。

实际上pyinstaller可以支持很多命令选项,我们现在重新打包一次,加一个选项:

pyinstaller --add-data "058.txt:." 058.py 

这里添加了--add-data "058.txt:."。解释一下:

  • --add-data表示后面要添加数据文件
  • 058.txt是要添加的数据文件,它后面的冒号以及后面的点.表示把这个文件添加到当前目录下。
  • 也就是说添加文件是成对出现,前面是要添加的文件,后面是添加的目标目录,中间用冒号隔开。
  • 可以添加多个文件,用分号隔开。

运行上面命令,会发现dist目录下多了数据文件:

Pyinstaller打包,彻底解决图片、数据路径问题

然后去运行058可执行文件:

maishu@msmacbook ~ % /Users/maishu/git/wx_maishucode/code/058/dist/058/058 ; exit;
当前python文件所在目录:/Users/maishu/git/wx_maishucode/code/058/dist/058
跟麦叔搞定路径问题
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

成功了!!

打成独立的文件:--onefile

上面是打包成了一个文件夹,发送给别人还是有点麻烦的。我们也可以直接打包成一个单独的文件:

pyinstaller --add-data "058.txt:." --onefile 058.py 

我们加了--onefile选项,表示打包成1个独立的文件。

运行后发现dist下面干净多了:

Pyinstaller打包,彻底解决图片、数据路径问题

运行一下,也能成功执行:

maishu@msmacbook ~ % /Users/maishu/git/wx_maishucode/code/058/dist/058 ; exit;
当前python文件所在目录:/private/var/folders/jw/ldvymnfj1zbbmngx3p8_zl_m0000gn/T/_MEIMaXGJM
跟麦叔搞定路径问题
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

解决更复杂的问题之路

pyinstaller有很多选项,我们在解决问题的时候可能会碰到更复杂的问题,我们3分钟讲不完。

如果你希望我更深入讲解,可以转发,点赞,嘻嘻。如果阅读和评论多,我可以考虑后续再出一个Pyinstaller终结者深度文章。

但是这里我就先指明几个方向,帮助你更有效的研究:

  • pyinstaller的官网上有很细致的讲解:https://pyinstaller.readthedocs.io/en/stable/spec-files.html。英语不好也可以用谷歌翻译。
  • pyinstaller打包的时候会首先生成一个spec文件,我们可以手工去修改这个文件,下次打包指定用这个文件。它的好处是:里面可以写更复杂的选项,也可以重录利用。spec文件的内容例子:# -*- mode: python ; coding: utf-8 -*-
    block_cipher = None
    a = Analysis(['058.py'],
    pathex=[],binaries=[],datas=[('058.txt''.')],
    hiddenimports=[],hookspath=[],hooksconfig={},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, [],exclude_binaries=True,
    name='058',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    console=True,
    disable_windowed_traceback=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None )
    coll = COLLECT(exe,a.binaries,a.zipfiles,a.datas, strip=False,
    upx=True,
    upx_exclude=[],name='058')

数据分析咨询请扫描二维码

客服在线
立即咨询