python 打包的 exe 程序自動更新


看了一下網友的思路,大致都如下:

  1. 運行主程序,同時檢查是否有更新

  2. 下載更新包

  3. 退出主程序

  4. 解壓更新包,覆蓋舊版本的文件(主程序退出以后,才能解壓覆蓋)

這里的問題就是如何覆蓋舊版本文件,因為 exe 不像 py 文件,py 文件運行時是可以自己刪除自己,或者覆蓋自身的,譬如:

test.py

import subprocess

subprocess.Popen('del test.py', shell=True)  # 運行后,會刪除自身:test.py

但是一旦你將它打包成 .exe 文件,就不行了。這是因為 exe 本身在執行時,文件是被占用的狀態,而我們不能在文件占用的時候刪除自身。

所以想要解決這個問題,就需要先制作一個程序,這個程序和主程序完全獨立,作為一個獨立的進程來運行。它專門用來進行更新包的解壓覆蓋,假設叫 update.exe, 下面是一個偽代碼,來模擬更新:

主程序:

if old_version < new_version:
    download(file)                 # 下載更新包
    subprocess.Popen('update.exe -args')  # update.exe 這個程序啟動時,可以先延遲兩秒,等待當前程序退出,然后自動去解壓更新包,來覆蓋主程序, 想要傳遞參數,可以將 update.exe 寫成一個可接受命令行參數的程序,來傳遞主程序的安裝位置等信息
    sys.exit()                     # 退出主程序

更新程序:update.exe

import time


def unzip(src, dst):
    ...


if __name__ == "__main__":
    time.sleep(2)
    unzip(src, dst)

下面的代碼來源於 CSDN博主「Linuxnot」https://blog.csdn.net/u013193899/article/details/78686039

這個例子更加簡潔直觀,它臨時寫一個 bat 文件,來刪除和運行新程序

import os
import sys
import subprocess 

#編寫bat腳本,刪除舊程序,運行新程序
def WriteRestartCmd(exe_name):
    b = open("upgrade.bat",'w')
    TempList = "@echo off\n";                           # 關閉bat腳本的輸出
    TempList += "if not exist "+exe_name+" exit \n";    # 新文件不存在,退出腳本執行
    TempList += "sleep 3\n"                             # 3秒后刪除舊程序(3秒后程序已運行結束,不延時的話,會提示被占用,無法刪除)
    TempList += "del "+ os.path.realpath(sys.argv[0]) + "\n"    # 刪除當前文件
    TempList += "start " + exe_name                     # 啟動新程序
    b.write(TempList)
    b.close()
    subprocess.Popen("upgrade.bat")
    sys.exit()                                         # 進行升級,退出此程序

def main():
    # 新程序啟動時,刪除舊程序制造的腳本
    if os.path.isfile("upgrade.bat"):
        os.remove("upgrade.bat")
    WriteRestartCmd("newVersion.exe")

if __name__ == '__main__':
    main()
    sys.exit()

打包的坑

當用 pyinstaller 打包成一個單獨的 exe 執行程序時,不要在腳本中使用 __file__ 來作為當前程序的路徑(打包成文件夾形式沒關系,但如果使用 pyinstaller -F 打包成單獨的exe就不行),在 .py 文件中這個路徑是正確的,但是一旦你將 .py 文件打包成 .exe, 這個路徑就不對了! 譬如下面的腳本:

print(__file__)

當作 py 文件運行時,結果為: C:\Users\UNCO9CA\Desktop\test\test.py,這是正確的路徑。

打包成單獨的 exe 文件時(即使用 pyinstaller -F test.py 選項打包):

C:\Users\UNCO9CA\Desktop\test\dist>test.exe
C:\Users\UNCO9CA\AppData\Local\Temp\1\_MEI114762\test.py  # 跟預想的不一樣!這是因為當打包成一個單獨的 exe 文件后,運行它時它會現在一個臨時文件夾解壓然后運行,所以路徑就變得不可知了。而且后綴依然是 .py 

因此,不要使用 __file__ 來獲取運行程序的路徑,而是使用: sys.argv[0]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM