这一篇博文中,主要讲解如何将python文件打包成exe文件。以下操作全部是在window10,python3.7.2的环境下操作。
这次博文,换一种方式讲解,与其说是试验吧。有如下几个问题:
- 要打包成exe文件,本身window需要什么样的环境支持?
- 环境支持的前提下,如何打包单python文件(只有一个.py文件)成exe文件?
- 环境支持的前提下,如何打包一个工程文件(多个.py文件以及文件夹)成exe文件?
- 环境支持的前提下,如何打包成一个集成的exe文件?如何打包成有依赖其他文件的exe文件?
问题一:要打包成exe文件,本身window需要什么样的环境支持?
在打包之前,首先是先保证这个python工程能在这个环境下正常的运行,可以正常运行说明程序运行需要的第三方库都有,这个非常重要!
再一个就是需要一个打包工具,这里我们选择pyinstaller。再cmd命令行模式,键入pyinstaller,如果提示没有该命令,那么就需要使用pip进行安装。最好先安装pywin32,因为pyinstaller依赖pywin32这个库,使用如下命令:
pip install pywin32
安装效果如下:
安装pyinstaller
pip install pyinstaller
安装效果如下图所示:
安装后,再在命令行上键入pyinstaller命令,正确安装就会有如下提示:
大致总结一下这些参数的意思:
故我们使用一个单文件的python文件来试验,如果缺少某个第三方库,看看是否可以打包成功?如果打包成功,是否可以运行?
以下是文件目录:
find.py源码为:
import os
import xlrd
import xlwt
import datetime
g_meters_docs_list = []
g_report_meters_list = []
g_buf = []
def get_datetime():
return str(datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S-%f'))
def get_meters_docs_list(meters_docs_file_path):
readbook = xlrd.open_workbook(meters_docs_file_path)
sheet = readbook.sheet_by_name('Sheet1')#名字的方式
nrows = sheet.nrows#行
ncols = sheet.ncols#列
for line in range(0, nrows):
str_line = str(sheet.cell(line,0))
str_line = str_line[7:]
str_line = str_line[:-2]
g_meters_docs_list.append(int(str_line))
def get_report_meters_list(report_meters_file_path):
readbook = xlrd.open_workbook(report_meters_file_path)
sheet = readbook.sheet_by_name('Sheet1')#名字的方式
nrows = sheet.nrows#行
ncols = sheet.ncols#列
temp_list = []
for line in range(0, nrows):
str_line = str(sheet.cell(line,0))
list_list = str_line[6:]
list_list = list_list[:-1]
# print (list(str_line))
#print (list_list)
temp_list.append(list_list)
for meters in temp_list:
meters = meters[2:]
temp_meter_lists = meters.split()
lens = len(temp_meter_lists)/6
for index in range(0,int(lens)):
temp_meter_list = temp_meter_lists[index*6:(index+1)*6]
temp_meter_list.reverse()
#print (temp_meter_list)
g_report_meters_list.append(int("".join(temp_meter_list)))
def file_compared():
g_buf = g_meters_docs_list
for meter in g_report_meters_list:
if meter in g_meters_docs_list:
g_buf.remove(meter)
print(g_buf)
with open("./output/" + get_datetime() + ".txt",'w') as f:
for meter in g_buf:
f.write(str(meter))
f.write("\r\n")
if __name__ == '__main__':
get_report_meters_list("./report_docs.xlsx")
#print (g_report_meters_list)
get_meters_docs_list(r"./meter_docs.xlsx")
#print (g_meters_docs_list)
try:
os.mkdir("./output")
except Exception as e:
print ("output folder exist")
file_compared()
os.system('pause') #按任意键继续
先在命令行上执行find.py文件,确定它是不能执行的,缺少xlrd这个库:
然后开始验证,在命令行进入到工程所在的路径,然后执行如下命令进行打包:
pyinstaller -F -w find.py
执行结果如图:
说明生成成功了。然后我们进到dist文件夹中,双击执行exe文件,提示脚本执行出错。
问题一结论:
打包前,必须保证脚本能在本环境下运行;其次,需要正确安装pyinstaller工具。
问题二:环境支持的前提下,如何打包单python文件(只有一个.py文件)成exe文件?
就拿上面的这个工程来试验,该工程就一个find.py文件,将它打包成一个可以运行的exe文件。因为上一个试验缺少xlrd库,所以我使用pip install xlrd将它安装回来,确保已经是可以运行的了。
在这之前,一定要把上次打包生成的文件以及文件夹(包括.spec、__pycache__、build、dist)都删除掉,不然它还是会使用上次打包生成的文件来生成新的exe文件,也就是说没有被更新过来。
确定删掉之后,在文件所在路径下,执行如下打包命令:
pyinstaller -F -w find.py
因为使用的是-F,生成的集成的exe文件,直接运行exe就可以。
因为运行需要两个excel文件,我单独拷贝进来的,运行的结果是生成一个output文件夹以及里面有个文件:
问题二结论:
单python文件使用pyinstaller -F -w find.py就能直接打包成exe文件。
问题三:环境支持的前提下,如何打包一个工程文件(多个.py文件以及文件夹)成exe文件?
这里我们使用我们的工程项目来试验。现在clone下来,做了一些更新,加上了图标文件夹 ,具体修改记录可以查看Git log。
源码目录结构如下:
在命令行模式下,进到当前工程路径,输入打包命令:
pyinstaller -F -i ./image/ico.ico -w main.py
打包成功,找到main.exe文件,发现文件有桌面图标了,正是我们image文件夹中的ico.ico文件。因为我们在打包的时候制定了把这个图标作为可执行文件的桌面图标。效果如下图:
双击exe可执行文件后,看箭头所指的地方,还是默认的程序图标,注意:这个和上面的桌面图标不是一个概念,这个程序图标需要在代码中编写指定。
self.main_window_obj.setWindowIcon(QIcon('./image/ico.png'))
正是image文件夹中的ico.png。如果我们没有把这个文件夹放到main.exe同一级目录下,双击main.exe文件,该程序图标还是不变。
然后我们把image文件夹放到与main.exe同一级目录下:
双击运行后,该程序图标已经更新过来:
问题三结论:
打包一个工程文件(多个.py文件以及文件夹)成exe文件,同样也是使用相同的命令,和单文件是一样的,不用担心它不会相互连接或者找不到的问题。
问题四:环境支持的前提下,如何打包成一个集成的exe文件?如何打包成有依赖其他文件的exe文件?
在上面的三个问题的试验中,我们都是生成一个集成的一个exe文件。因为我们在打包的时候指定的是-F,生成单可执行文件。如果我们把-F改为-D,就是把工程文件打包成需要依赖其他文件才能运行的可执行文件。
例如使用如下命令打包:
pyinstaller -D -i ./image/ico.ico -w main.py
打包成功后,看到dist文件夹中包含main文件夹。而main文件中的全部文件,正是main.exe运行所需要的依赖文件。
问题四结论:
设置好打包的参数,就可以决定生成单文件的可执行文件还是需要依赖文件才能运行的可执行文件。