使用 pyinstaller 打包程序及路径问题.

最近有一门课的小组任务要求完成 AES 加密算法,语言不限,并且提交一个完整的工程和测试程序,还要附上 README。因为对我来说难度稍微低一些,我就直接把这个给做完了。(微笑)

为了锻炼一下我的 Java 水平和能力,所以我一开始打算全部用 Java 来写,但后来因为偷懒不想写为了展现我们灵活而全面的技术栈,所以我就用 Python 写了一个文件对比的脚本。

pyinstaller 的安装

考虑到 Windows 各种各样的使用环境,我们直接发一个 .py 的脚本是不一定能够在其他电脑上正常运行的。因此为了方便就必须要给程序做打包,把 Python 的环境全部打包到一个二进制文件里面,这样就能够做到独立运行了。

pyinstaller 是一个专门用来做 Python 脚本打包的库,如果没有可通过 pip install pyinstaller 进行安装。

这里建议使用虚拟环境去安装 pyinstaller,它会根据环境中的库情况进行打包,如果使用的库多了会导致打包出来的程序会特别地大。如果在虚拟环境中做库的删改都会更加方便。

开始打包!

完成安装后就可以开始打包的操作了,首先需要 cd 到 .py 文件对应的目录文件夹,这样就可以保证生成出来的文件都在目录里面,整理比较方便。

pyinstaller 常用的命令有两个:

pyinstaller -D app.py
pyinstaller -F app.py

其中的 app.py 为要打包文件的相对地址,-D 是默认命令,即生成一个目录文件,里面包含了一个启动程序和一系列的依赖文件;-F 是生成单个可执行文件的命令,它生成 builddist 文件夹,其中 dist 文件夹里面的可执行文件是可以单独使用的,其余项可以删掉。

它的原理很简单粗暴,就是将 Python 复制出来,连着脚本一起打包进去,执行的时候再全部解压到缓存文件夹里执行脚本文件。

路径问题

打包完成之后就可以拿出来使用了,因为里面集成了 Python 的 runtime 环境,所以不管电脑里面有没有装 Python,各种姿势使用都不会影响。

正当我以为完成之时,打开程序直接闪退。从 CMD 打开才发现程序出现了错误,要访问的文件访问不到,这时我才发现程序执行的目录(一个在 Roaming 中的缓存目录)和这个程序放的目录不是一致的,所以直接用相对地址根本访问不到所需要的文件。

不过幸好 Python 还是有解决办法的,就是获取执行文件所在的路径。

os.path.dirname(os.path.realpath(sys.executable))
os.path.dirname(os.path.realpath(sys.argv[0]))

利用 os 库中的这两个命令都可以返回该执行文件的绝对地址,然后再加在前面就可以解决问题了。

如何减小包的体积

如何减小 pyinstaller 打包程序的体积,这是一个十分具有优化量的工作。我的思路大致如下:

  1. 建立虚拟环境去进行打包;
  2. 如果能够 import … from …,就不要 import 整个库,不然也会一起打包;
  3. 能合起来的功能就合起来,分开打包的同时也会分别集成 Python 环境;
  4. 能引用外部文件的地方就引用外部文件。

如果体积还是超标,可以考虑换一个框架,比如 UWP 之类的因为 Windows 系统自带框架,所以出来的文件体积都很小。而 eletron 和 swing 这些框架它本身也是要集成一个 Chromium 或者 JDK 的独立环境,所以体积都不小,通常 60M 起步,不过像 VSCode 这样老大哥级别的开发团队,可以通过玄学压缩的方式给 eletron 压到 30M+,还是十分有实力的,在优化上也没小下功夫。