cx_Freeze: LookupError: unknown encoding: cp437

cx_Freeze: LookupError: unknown encoding: cp437

我使用 cx_Freeze 创建我的软件的 exe,我需要实现一个自动更新程序。所以到目前为止我所做的是检查是否有软件的更新版本,以及是否有程序应该下载包含更新的 zip 文件。到目前为止,一切都很好。但是当通过解压缩 zip 文件来安装更新时,我 运行 进入 LookupError:

  File "C:\Program Files (x86)\Python37-32\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
  File "Rocketupload.py", line 1947, in download
  File "C:\Program Files (x86)\Python37-32\lib\zipfile.py", line 1222, in __init__
    self._RealGetContents()
  File "C:\Program Files (x86)\Python37-32\lib\zipfile.py", line 1327, in _RealGetContents
    filename = filename.decode('cp437')
LookupError: unknown encoding: cp437

Rocketupload 第 1947 行:

z = zipfile.ZipFile(file_name, allowZip64=True)

奇怪的是,当我 运行 使用 shell 的软件时,没有 cx_Freeze 创建的 exe 时,我没有遇到同样的问题。所以我认为问题与exe的创建有关。

我还将提供用于下载和解压缩更新版本 zip 的代码:

def download(self):
    exePath = sys.argv[0]
    self.downloadBtn.configure(state="disabled")
    file_name = SettingsManager.find_data_file("RocketUpload_v" + str(self.versionNumber) + ".zip")
    with open(file_name, "wb") as f:
        response = requests.get(self.downloadFile, stream=True)
        print(response)
        total_length = response.headers.get('content-length')

        dl = 0
        total_length = int(total_length)
        for data in response.iter_content(chunk_size=4096):
            downloadedSize = str(round(int(dl) / self.MBFACTOR, 2))
            if (downloadedSize[-3]) != ".":
                downloadedSize += "0"

            self.progressVar.set("RocketUpload_v" + str(self.versionNumber) + " Downloading: [" + downloadedSize + "MB/" + str(round(int(self.maximum) / self.MBFACTOR, 2)) + "MB]")
            dl += len(data)
            self.num.set(dl)
            self.parent.update()
            f.write(data)
        self.progressVar.set("RocketUpload_v" + str(self.versionNumber) + " Finished: [" + str(round(int(self.maximum) / self.MBFACTOR, 2)) + "MB/" + str(round(int(self.maximum) / self.MBFACTOR, 2)) + "MB]")
        time.sleep(1)
        self.progressVar.set("RocketUpload_v" + str(self.versionNumber) + ": Installing...")
        f.close()

    excluded = set(["rsc"])
    for root, dirs, files in os.walk(SettingsManager.find_data_file("."), topdown=True):
        dirs[:] = [d for d in dirs if d not in excluded]
        for filename in files:
            file_path = os.path.join(root,filename)
            if file_path[-4:] != ".zip":
                os.rename(file_path, file_path + ".tmp")

    time.sleep(2)

    z = zipfile.ZipFile(file_name, allowZip64=True) #<---- That is where the error happens
    uncompress_size = sum((file.file_size for file in z.infolist()))
    print(uncompress_size)
    self.progress.configure(maximum=uncompress_size)
    self.num.set(0)
    extracted_size = 0

    for file in z.infolist():
        self.progressVar.set("RocketUpload_v" + str(self.versionNumber) + " Installing: [" + str(int(extracted_size/uncompress_size*100)) + "%/100%]")
        extracted_size += file.file_size
        self.num.set(extracted_size)
        self.parent.update()
        z.extract(file)

    self.progressVar.set("RocketUpload_v" + str(self.versionNumber) + " Installing: [100%/100%]")
    self.parent.update()
    time.sleep(0.5)

    self.progressVar.set("RocketUpload_v" + str(self.versionNumber) + " Installing: Finished. Relaunch App Now.")
    self.parent.update()
    self.finished = True
    f.close()

我想做的是将有关 运行ning 软件的所有文件重命名为临时文件,然后解压缩 zip 文件,因为它不允许覆盖打开的文件。

这是我的 setup.py 用 cx_Freeze 冻结我的软件:

import sys
import setuptools
from cx_Freeze import setup, Executable

# GUI applications require a different base on Windows (the default is for a
# console application).
base = None
if sys.platform == "win32":
    base = "Win32GUI"

setup(  name = "RocketUpload",
        version = "1.0",
        options = {
            "build_exe": {
                "packages": ["os","time","csv","sys","shutil","re","random","pickle","traceback", "autoit", "ctypes", "threading", "_thread", "configparser", "platform", "subprocess", "queue", "multiprocessing", "psutil", "datetime", "webbrowser","PIL","tkinter","cryptography","abc","selenium", "bs4", "requests", "zipfile"],
                'includes': ['Rocketupload','paywhirl'],
                'include_msvcr': True,
            },
        },
        executables = [Executable("Rocketupload.py", base=base,icon = "rsc/imgs/LogoBlackIcon.ico")]
        )

我的预期结果是能够解压缩我下载的 zip 文件。

尝试将 "encodings" 添加到 setup.py 脚本中的 packages 列表:

"packages": ["encodings", "os","time","csv","sys","shutil","re","random","pickle","traceback", "autoit", "ctypes", "threading", "_thread", "configparser", "platform", "subprocess", "queue", "multiprocessing", "psutil", "datetime", "webbrowser","PIL","tkinter","cryptography","abc","selenium", "bs4", "requests", "zipfile"],

引用 cx_Freeze 的主要开发人员在 quite old issue 中的回答:

You need to add the option "--include-modules encodings.cp437" on your command line as this module is loaded dynamically at runtime (so static analysis cannot catch that).

如果您没有使用最新的 cx_Freeze 版本 (6.0),也许将 cx_Freeze 更新到此版本可能足以解决问题。