python打包exe工具
Python打包工具主要有三种:py2exe、PyInstaller和cx_Freeze。其实是三种工具,并且实现打包的方法都是邯郸小异。无非将Python运行所需的基础dll文件和源码依赖的模块筛选后聚合在一起,进而达到脱离环境单独运行的目的。但其中比较新奇的是它们竟然可以将最终代码打包成单个文件去运行,简直不要太神奇。
清风常用的打包工具为pyinstaller,安装下载简单,网上的文档也很齐全。
打包的exe怎样执行
即便你们看见python打包exe工具的优势,还会提及一句打包成单个文件,可以保护源码不泄露。对于菜鸟来说linux 执行exe文件,这个理由完美,单个文件如何操作觉得也不会获得源码,但我只能说,天真啊!
pyinstaller的官方文档:
pyinstaller.readthedocs.io:HowtheOne-FileProgramWorks
中有相关内容的详尽说明,为了便捷,我简单翻译下:
引导加载程序也是单文件捆绑包的核心。启动后,它将在此操作系统的相应临时文件夹位置中创建一个临时文件夹。该文件夹名为_MEIxxxxxx其中xxxxxx是一个随机数。一个可执行文件包含脚本使用的所有Python模块的嵌入式归档,以及任何非Python支持文件(比如,.so文件)的压缩副本。引导加载程序解压缩支持文件linux find,并将副本写入临时文件夹。这可能须要一些时间。这就是为何单文件应用程序比单文件夹应用程序启动慢的诱因。
所以单个的exe文件在执行时,会先在系统临时目录下创建一个_MEI开头的文件夹,之后解压源码、依赖文件后,运行该临时文件夹下的内容。
其中windows的临时文件夹一般为:
C:WindowsTemp_MEIxxxx或
C:Users用户名AppDataLocalTemp_MEIxxxx
但经过多次测试,几乎全在前者的目录下。似乎只要在cmd下输入echo%temp%或则%tmp%才能确定了...
windwos临时目录
Linux的临时文件夹目录自然是在:
**/tmp/_MEIxxxxx**
其实,假如每次exe执行时,就会创建临时文件夹,但执行完成后又不销毁,岂不是早就引起我们的笔记本c盘空间溢出了。所以官方是有说明的:
创建临时文件夹后,引导程序将在临时文件夹的上下文中继续与单文件夹捆绑软件一样进行。当捆绑的代码中止时,引导加载程序将删掉临时文件夹。
假如程序崩溃或被杀害,则不会删掉该文件夹(在Unix上为kill-9,在Windows上为TaskManager杀害linux 执行exe文件,在MacOS上为“ForceQuit”)。为此,假若您的应用程序频繁崩溃,则用户将遗失c盘空间到多个临时文件夹。_MEIxxxxxx_MEIxxxxxx
打包Flask项目
pyinstalelr的基础使用就不在这儿过多介绍了,之前的文章有过详尽的说明:
Python打包工具--Pyinstaller详尽介绍:
我们只须要晓得pyinstaller-F(onefile)参数即可将代码最终打包为单个的exe文件即可。
然而Flask的static、templates该如何打包呢?让我们以之前开发过的一个FlaskHttpserver为例说明。
首先看下代码结构:
Flask代码目录
settings中放了Flask的一些config配置,manage.py通过新蓝图注册HttpServer中views下的account与home模块。这么,如今我们须要将代码中的static、templates、settings(测试发觉这个配置文件也没办法手动打包,须要自动追加)成单个文件呢?pyinstaller提供了一个[--add-data]的参数,整体打包命令如下:
pyinstaller -F -i BreezePython.ico --add-data="HttpServerstatic;HttpServerstatic" --add-data="HttpServertemplates;Httpservertemplates" --add-data="settings.py;." manage.py
原理就是保持代码中的路径一致,倘若是当前路径使用.进行替换。
有些人认为这个一个一个的添加太麻烦了,这么还有另一种思路。来瞧瞧我们打包后的目录:
spec文件的妙用
打包完成后,会生成一个main应用.spec的文件,通过我们昨天一顿--add-data的操作后,spec有哪些区别么?
通过datas添加数据
所以我们可以换另一种方法加载依赖文件:
首次打包时直接-F完成打包编辑*.spec文件,通过在列表中添加对应元祖信息的方法,追加以来稳健pyinstaller-F*.spec进行二次打包即可追加文件至exe中。
来让我们瞧瞧打包后的exe是否可以执行吧:
打包疗效展示
OK,一个exe文件拉起整个Flask项目,带着exe我们就可以脱离环境单独运行我们的HTTPServer了。是不是很拉风?
临时文件监控复制
初次测试,可能存在打包路径错误的问题,每次去找临时路径查看太麻烦了,既然写代码linux服务器搭建,不如顺手写个动态监控_MEI路径并完成循环复制的功能,具体实现如下:
判定笔记本的操作系统while循环监控临时目录启动exe工具获取exe创建的_MEI开头文件夹将该临时文件夹拷贝到执行目录
最终代码实现如下:
# -*- coding: utf-8 -*- # @Author : 王翔 # @微信号 : King_Uranus # @公众号 : 清风Python # @GitHub : https://github.com/BreezePython # @Date : 2020/11/17 23:50:09 # @Software : PyCharm # @version :Python 3.7.3 # @File : get_source_code.py import platform import os import time import shutil def get_tmp_path(): if platform.platform().lower().startswith('windows'): return os.getenv('temp') else: return '/tmp' class GetSourceCode: def __init__(self): self.base_path = os.path.dirname(__file__) self.tmp_path = get_tmp_path() self.basic_dirs = self.get_dirs() self.code_dir = None def get_dirs(self): for root, dirs, files in os.walk(self.tmp_path): return set(dirs) def get_source_dir(self): while True: _dir = list(self.get_dirs() - self.basic_dirs) if _dir and _dir[0].startswith('_MEI'): self.code_dir = _dir[0] print("find source code dir %s" % self.code_dir) break else: time.sleep(0.2) self.copy_code_dir() def copy_code_dir(self): abs_tmp_path = os.path.join(self.tmp_path, self.code_dir) while os.path.exists(abs_tmp_path): source_path = os.path.join(self.base_path, self.code_dir) if not os.path.exists(source_path): os.mkdir(source_path) for root, dirs, files in os.walk(abs_tmp_path): for file in files: remote_path = root.replace(abs_tmp_path, source_path).replace('\', '/') if not os.path.exists(remote_path): print(remote_path) os.makedirs(remote_path) if not os.path.exists(remote_path + '/' + file): shutil.copy(os.path.join(root, file), remote_path) print("Get source code end.") if __name__ == '__main__': print("start Source Code Analyse project.") print("Monitoring source files...") g = GetSourceCode() g.get_source_dir()
瞧瞧疗效怎么:
动态拷贝源码数据
ok,快把你积攒已久的代码筛选下,瞧瞧这些适宜打包成exe,拿去给同学们显摆吧!