python 打包exe程序

安装python环境

https://www.python.org/downloads/windows/

安装pyinstaller

pip install pyinstaller

准备python源码


from tkinter import Tk
from tkinter import Button
from tkinter import INSERT
from tkinter import END
from tkinter import WORD
from tkinter import BOTH
from tkinter.scrolledtext import ScrolledText
import tkinter.filedialog
import tkinter.messagebox
import xml.dom.minidom
import os
import re
import string

g_timeout = 4   # 4秒超时


# 通讯参数
g_param = {
    "ProtocolType": "0x00",
    "PHYPort": "0x00",
    "FunctionAddress": "0x00",
    "ECUAddress": "0x00",
    "TesterAddress": "0xF1",
    "Baudrate": "500",
    "TIdle": "300",
    "TWup": "50",
    "P1Min": "0",
    "P1Max": "20",
    "P2Min": "25",
    "P2Max": "50",
    "P3Min": "55",
    "P3Max": "5000",
    "P4Min": "5",
    "P4Max": "20",
    "CanPhysReqId": "0x710",
    "CanFuncReqId": "0x7DF",
    "Equipment_Serv_Id": "0x00",
    "Ecu_Time_T1": "0x00",
    "Ecu_Time_T2": "0x00",
    "Ecu_Time_T3": "0x00",
    "Ecu_Time_T4": "0x00",
    "Tester_Time_T1": "0x00",
    "Tester_Time_T2": "0x00",
    "Tester_Time_T3": "0x00",
    "Tester_Time_T4": "0x00",
}

# 日志中解析的报文结构
class Packet:
    id = ""
    thread = ""
    process = ""
    time = 0
    content = []
    content_string = ""
    valid = True

    def __init__(self, id, thread, process ,content, content_string, time):
        self.id = id
        self.thread = thread
        self.process = process
        self.content = content
        self.content_string = content_string
        self.time = time

# 对应xml
class Service:
    req = ""
    res = ""

    def __init__(self, req, res):
        self.req = req
        self.res = res

# 对应xml
class Section:
    name = ""
    sid = ""
    rid = ""
    services = []

    def __init__(self, sid, rid):
        self.name = sid + "_" + rid
        self.sid = sid
        self.rid = rid
        self.services = []

class Main():
    packets = []
    xmlFile = []

    def __init__(self):
        self.win = Tk()
        self.initWin()
        self.log = ScrolledText(self.win, wrap=WORD, height=40)
        self.log.pack(side="bottom", fill=BOTH)
        self.initBtn()
        self.win.mainloop()

    def initWin(self):
        self.win.title("Log")
        self.win.geometry("600x600")
        self.win.resizable(width=False,height=False)

    def initBtn(self):
        Button(self.win, text="选择日志文件..", command=self.GetResource).place(x=10, y=10)
        Button(self.win, text="导出结果文件", command=self.GenerateXML).place(x=110, y=10)

    # 打开文件 获取所有报文内容
    def GetResource(self):
        default_dir = r"C:\\"
        self.filePath = tkinter.filedialog.askopenfilename(title=u'选择文件', initialdir=(os.path.expanduser(default_dir)))

        try:
            f= open(self.filePath,  'r', encoding='UTF-8', errors='ignore')
        except IOError as e:
            Tk.messagebox.showerror(title = '错误', message='打开文件失败')
            return
        
        patternPacket = re.compile('^[A-Z]+ ([0-9]*) (?P<time>[0-9]*)\.([0-9]*) (?P<thread_num>[a-zA-Z0-9]*)::(?P<process_num>[a-zA-Z0-9]*) \[([a-zA-Z]*)\] OS[<|>] (?P<id>[a-zA-Z0-9]*) (?P<content>[^"]*)')
        patternOdbParam = re.compile('^[A-Z]+ ([0-9]*) ([0-9]*)\.([0-9]*) ([a-zA-Z0-9]*)::([a-zA-Z0-9]*) \[([a-zA-Z]*)\] ObdOpen\(port=([0-9]*),proto=([0-9]*),rate=([a-zA-Z0-9]*),fadr=([a-zA-Z0-9]*),eadr=([a-zA-Z0-9]*),tadr=([a-zA-Z0-9]*),sid=0x(?P<sid>[a-zA-Z0-9]*),rid=0x(?P<rid>[a-zA-Z0-9]*)\)')
        
        self.log.delete(0.0, END)
        lines = f.readlines()
        for line in lines:
            if (-1 != line.find("[vcicore] ObdOpen(port=")):
                regMatch = patternOdbParam.match(line)
                if None != regMatch:
                    linebits = regMatch.groupdict()
                    sid = linebits['sid']
                    rid = linebits['rid']
                    # 去重
                    if (self.RemoveDuplication(sid, rid)):
                        section = Section(sid, rid)
                        self.xmlFile.append(section)
            if (-1 != line.find("[vcicore] OS")):
                regMatch = patternPacket.match(line)
                if None != regMatch:
                    linebits = regMatch.groupdict()
                    content_string = content = linebits['content'].replace("\n","")
                    content = content_string.split(' ')
                    # 36刷写报文只取部分
                    if (len(content) > 20
                    and content[0] == "36"):
                        content = content[:3]
                        content_string = content_string[:8]
                    packet = Packet(linebits['id'], linebits['thread_num'], linebits['process_num'], content, content_string, int(linebits['time']))    
                    self.log.insert(INSERT, linebits['id']+ " " +content_string +'\n')
                    self.packets.append(packet)
        f.close()

    # 生成xml文件
    def GenerateXML(self):
        cnt = 0
        for element in self.xmlFile:
            self.Organize(element)
            if (len(element.services) != 0):
                self.CreateFile(element)
                cnt = cnt + 1
        tkinter.messagebox.showwarning(title = '完成',message='共生成'+str(cnt)+'个文件')
        self.filePath = ""

    # 判断是否重复
    def RemoveDuplication(self, sid, rid):
        for e in self.xmlFile:
            if (sid == e.sid and rid == e.rid):
                return False
        return True

    # 验证是否是对应的收发报文
    def Calibrate(self, req, res):
        if (req.process == res.process and req.thread == res.thread):
            if (len(req.content) > 0 and len(res.content) > 0):
                    if (res.content[0] == "7F"): #7F的特殊情况
                        return True
                    if (64 == int(res.content[0], 16) - int(req.content[0], 16)):
                        return True
        return False

    # 整理报文对应的文件
    def Organize(self, section):
        cnt_record = 0

        while (True):
            if (0 == len(self.packets)):
                break   # 报文列表为空,退出

            #找到一个发送id
            cnt_sid = -1
            index = cnt_record
            while (index < len(self.packets)):
                if (self.packets[index].valid
                    and section.sid == self.packets[index].id):
                    cnt_sid = index
                    #找到的发送报文设置无效标记
                    self.packets[index].valid = False
                    break
                index += 1
                cnt_record = index
            
            #sid未找到,列表中没有需要的报文,退出
            if (-1 == cnt_sid):
                break

            #找到报文发送id对应的接收id
            cnt_rid = -1
            index = cnt_sid + 1
            sid_head = self.packets[cnt_sid].content[0] #发送报文的头部
            max_time = self.packets[cnt_sid].time + g_timeout #最大寻找时间
            while (index < len(self.packets)):
                if (self.packets[index].valid
                    and section.rid == self.packets[index].id
                    and self.packets[index].time < max_time):
                    #判断是延时帧(7F xx 78)
                    if (len(self.packets) > 2
                        and self.packets[index].content[0] == "7F"
                        and self.packets[index].content[1] == sid_head
                        and self.packets[index].content[2] == "78"):
                        max_time = self.packets[index].time + g_timeout # 更新超时时间,以当前78报文为准
                        self.packets[index].valid = False # 78报文设置无效标记
                        index += 1
                        continue
                    if (self.Calibrate(self.packets[cnt_sid], self.packets[index])): # 通过线程号等验证是否是对应的接收报文
                        cnt_rid = index # 找到了接收的报文
                        break
                index += 1

            #rid未找到,超时
            if (-1 == cnt_rid):
                continue

            #添加列表
            svc = Service(self.packets[cnt_sid].content_string, self.packets[cnt_rid].content_string)
            self.log.see(END)
            section.services.append(svc)
            self.packets[cnt_rid].valid = False

    # 创建xml文件
    def CreateFile(self, resultFile):
        impl = xml.dom.minidom.getDOMImplementation()
        # 设置根结点
        dom = impl.createDocument(None, 'ECU', None)
        root = dom.documentElement
        root.setAttribute("name", resultFile.name)

        # 根节点添加子节点COMMPARAMETERS
        commparameters = dom.createElement('COMMPARAMETERS')
        root.appendChild(commparameters)

        # 设置通讯参数
        for key, value in g_param.items():
            nameE=dom.createElement('PARAM')
            nameE.setAttribute("name", key)
            nameE.setAttribute("value", value)
            commparameters.appendChild(nameE)
    
        # 设置canid
        nameE=dom.createElement('PARAM')
        nameE.setAttribute("name", "CANSID")
        nameE.setAttribute("value",resultFile.sid)
        commparameters.appendChild(nameE)

        nameE=dom.createElement('PARAM')
        nameE.setAttribute("name", "CANRID")
        nameE.setAttribute("value", resultFile.sid)
        commparameters.appendChild(nameE)

        # 根节点添加子节点SECTIONS
        sections = dom.createElement('SECTIONS')
        root.appendChild(sections)

        # SECTION
        section=dom.createElement('SECTION')
        sections.appendChild(section)

        for svc in resultFile.services:
            #SERVICE
            service=dom.createElement('SERVICE')
            section.appendChild(service)
            #REQ
            req=dom.createElement('REQ')
            reqTxt=dom.createTextNode(svc.req)  #内容
            req.appendChild(reqTxt)
            service.appendChild(req)
            #RES
            res=dom.createElement('RES')
            resTxt=dom.createTextNode(svc.res)  #内容
            res.appendChild(resTxt)
            service.appendChild(res)
    
        f= open(resultFile.name + '.xml', 'w') #w替换为a,追加
        dom.writexml(f, addindent='\t', newl='\n')
        f.close()

if __name__ == '__main__':
	Main()

打包程序

# -w 隐藏控制台
pyinstaller -F -w program.py

posted @ 2020-08-28 13:54  熊云港  阅读(377)  评论(0编辑  收藏  举报