pyinstaller和py2exe生成exe文件并添加版本信息和自定义图标

pyinstaller和py2exe把Python脚本生成exe文件,

并添加版本信息和自定义图标。

写了一个查找产品通道号的小程序,目前还没进行异常处理。
以下是程序源码。

另外一个地址
http://blog.rayuu.com/pyinstaller_py2exe_exe.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186

# -*- coding:UTF-8 -*-
import serial
import time
# import argparse
import serial.tools.list_ports
from time import sleep
 
 
# 串口
class Serial(object):
def __init__(self):
print u"+++++++++++++++++++++++++++++++++++++++++"
print u"+ 通道号查找程序 +"
print u"+ V1.0 +"
print u"+ by:Rayu +"
print u"+ 2016.09.27 +"
print u"+++++++++++++++++++++++++++++++++++++++++"
 
# 查找串口
def serial_find(self):
plist = list(serial.tools.list_ports.comports())
if len(plist) <= 0:
print u"串口未发现!"
else:
print u"找到的串口如下:"
for i in range(0, len(plist)):
print [i+1], plist[i]
print u"请输入对应的数字选择你想要使用的串口:<默认为1>"
number = raw_input()
if not number:
number = 1
number = int(number)
while number > len(plist):
print u"串口未找到,请重新输入。"
print u"请输入对应的数字选择你想要使用的串口:"
number = raw_input()
number = int(number)
if number <= len(plist):
uart_choose = plist[number-1][0]
return uart_choose
 
# 串口波特率
def serial_baudrate(self):
print u"请输入串口波特率:<默认115200>"
baudrate = raw_input()
if not baudrate:
baudrate = 115200
baudrate = int(baudrate)
return baudrate
 
# 获取设备地址
def input_dev_addr(self):
print u'请输入设备地址:<如:dc00000233>'
data_dev = raw_input()
# print data_dev, type(data_dev)
return data_dev
 
# 打开串口
def serial_open(self, com, baud):
try:
ser = serial.Serial(com, baud, timeout=0.1)
except Exception, e:
print u"打开串口失败,请检查串口是否被占用。\n5秒后自动退出程序"
time.sleep(5)
exit(1)
print u"串口", com, u"打开成功......波特率为:", baud
sleep(0.5)
return ser
 
# 更改通道号
def serial_send_channel(self, com, baud, dev, sta):
#
data_comm = "AB"
data_sum = "01"
# 通道号修改
ser = self.serial_open(com, baud)
start = time.clock()
for data_channel in range(0, 256):
# 转换为十六进制字符串
dev_channel = hex(data_channel)
# 把0x删掉
dev_channel = dev_channel[2:4]
if len(dev_channel) == 1:
dev_channel = '0' + dev_channel
# 连接字符串
content_addr = data_comm+dev_channel+data_sum
# print content_addr,"content_addr",type(content_addr)
# 十六进制发送
content_addr = content_addr.decode("hex")
# print content_addr
# print u"开始发送数据..."
ser.write(content_addr)
 
lowerpower = int(sta)
# sta = self.serial_send_order(ser,DEV)
re_str = []
cou = 0
find_time = data_channel + 1
print u"进行第 %s" % find_time, u"次查找....."
i = 1
while i <= 10:
i += 1
for c in ser.read():
# re_str += c
re_str.append(c)
cou += 1
if cou == 10:
# print re_str,"re_str"
re_str = []
break
 
content_order = self.serial_send_order(dev)
if lowerpower == 1:
print u"低功耗设备,6秒发一次"
ser.write(content_order)
time.sleep(6)
else:
# time.sleep(0)
ser.write(content_order)
 
line = []
cnt = 0
j = 1
while j <= 10:
j += 1
for d in ser.read():
line.append(d)
cnt += 1
if cnt == 10:
# print "line",line
# line = []
# print data_channel
print u"查找结束......"
end = time.clock()
print u"用时: %f s" % (end-start)
line[8] = ord(line[8])
# print ord(line[8])
ser.close()
return line[8]
end = time.clock()
print u"用时: %f s" % (end - start)
print u"未找到通道号,请确定设备地址和工装是否正常......"
ser.close()
return -1
 
# 发送通信命令
def serial_send_order(self, dev):
# 发送通信测试命令
data_head = "F01"
data_dev = dev
data_tail = "E3"
# print data_dev
data_addr = data_head + data_dev + data_tail
# data_addr = "F0"
data_addr = data_addr.decode("hex")
return data_addr
 
if __name__ == '__main__':
comm = Serial()
# 获取COM口
COMM = comm.serial_find()
# print COMM
BAUD = comm.serial_baudrate()
while True:
DEV = comm.input_dev_addr()
if DEV == 'q':
exit()
print u"低功耗设备请输入1,否则请直接按回车......\n输入q结束程序......"
sta = raw_input()
if not sta:
sta = 0
channel = comm.serial_send_channel(COMM, BAUD, DEV, sta)
if channel == -1:
print u"查找失败......请重新尝试......"
else:
channel = hex(channel)
print u"通道号为: ", channel
 
# comm.serial_send_order(DEV)
# print BAUD
# comm.serial_open(COMM, BAUD)
# parser = argparse.ArgumentParser(description="通道号查找程序")
# parser.add_argument('--port', action='store', dest='port', type=int, required=True)
# given_args = parser.parse_args()
# port = given_args.port

程序编写完成后,生成exe可执行文件。

首先利用py2exe进行转换。

1).新建setup.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# -*- coding: utf-8 -*-
__author__ = 'Rayu'
from distutils.core import setup
import py2exe
includes = ["encodings", "encodings.*"]
options = {"py2exe": {"compressed": 1, "optimize": 2, "includes": includes, "bundle_files": 1}}
setup(
version = "0.1.0",
description = u"[利用工装查找设备通道号]",
name = "FindChannel",
options = options,
zipfile = None,
# 生成有指定图标的exe
console = [{"script": "main.py",
"icon_resources": [(1, u"833.ico")]
}]
# 生成无图标exe
# windows = [{"script": "[源码文件名].py"}]
)
 
# from distutils.core import setup
# import py2exe
#
# setup(console=['main.py'])

然后运行程序 python setup.py py2exe

在64位系统下运行会报错: bundle_files:1 在64位操作系统下无效。 这句话的意思就是生成单文件程序。

所以64位操作系统下想生成单文件程序的可以改用pyinstaller.

2).利用pip install PyInstaller 或者去官网下载安装包。

我安装的PyInstaller3.2版本。

安装完成后,在命令窗口下执行:

pyinstaller main.py

会在当前文件夹的dist目录下生成main文件夹,里面的main.exe就是生成的可执行文件。

main文件夹整个复制出来就可以在其他地方运行了。

如果想为程序添加自定义图标和版本信息,那么在main.py的目录下,会有一个main.spec文件,使用notepad++打开进行编辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# -*- mode: python -*-
 
block_cipher = None
 
 
a = Analysis(['main.py'],
pathex=['C:\\Users\\jx007\\Desktop\\commserial'],
binaries=None,
datas=None,
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='FindChannel',
version='version.txt',
debug=False,
strip=False,
upx=True,
console=True , icon='833.ico')

a.datas, 下面添加

version='version.txt',
icon='833.ico',

然后保存。

先不要执行,然后把你心仪的ico图标放到和main.py同一目录下,version是版本信息路径。

名称为version.txt

这时候我们需要编写version.txt

下面是一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# UTF-8
#
VSVersionInfo(
ffi=FixedFileInfo(
# filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4)
# Set not needed items to zero 0.
filevers=(6, 1, 7600, 16385),
prodvers=(6, 1, 7600, 16385),
# Contains a bitmask that specifies the valid bits 'flags'r
mask=0x3f,
# Contains a bitmask that specifies the Boolean attributes of the file.
flags=0x0,
# The operating system for which this file was designed.
# 0x4 - NT and there is no need to change it.
OS=0x40004,
# The general type of file.
# 0x1 - the file is an application.
fileType=0x1,
# The function of the file.
# 0x0 - the function is not defined for this fileType
subtype=0x0,
# Creation date and time stamp.
date=(0, 0)
),
kids=[
StringFileInfo(
[
StringTable(
u'040904B0',
[StringStruct(u'CompanyName', u'Microsoft Corporation'),
StringStruct(u'FileDescription', u'Windows Command Processor'),
StringStruct(u'FileVersion', u'6.1.7600.16385 (win7_rtm.090713-1255)'),
StringStruct(u'InternalName', u'cmd'),
StringStruct(u'LegalCopyright', u'© Microsoft Corporation. All rights reserved.'),
StringStruct(u'OriginalFilename', u'Cmd.Exe'),
StringStruct(u'ProductName', u'Microsoft® Windows® Operating System'),
StringStruct(u'ProductVersion', u'6.1.7600.16385')])
]),
VarFileInfo([VarStruct(u'Translation', [1033, 1200])])
]
)

如果你想要自己找这个文件的话,可以参考pyinstaller3的文档,里面写的很详细。

下面简单介绍一下如何获取这个文件。

首先在文档里面写到了,利用 pyi-grab_version executable_with_version_resource 这个命令来获取命令的版本信息。

我们运行 pyi-grab_version c:/windows/system32/cmd.exe

然后会把一个file_version_info.txt记事本文件保存在你cmd命令运行时候的路径下面。
找到并打开它,就是上面所列出的内容了。
然后根据自己的需要进行修改就可以了。
最后在main.py的路径下执行

pyinstaller main.spec

dist文件夹下就产生了一个exe文件,图标也是我们想要的那个图标了,至于程序的详细信息可以通过右键查看详细信息进行查看了。

详细信息

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器