求助:Python zipfile模块为何仅提取单个文件?
解决Python更新器提取ZIP文件仅提取一个就停止的问题
问题核心原因
你的代码中途停止提取主要有三个问题:
- 未处理文件覆盖异常:
zipfile.ZipFile.extract()默认不会覆盖已存在的文件,遇到已有文件时会直接抛出FileExistsError,导致程序终止。 - UI线程阻塞:循环提取文件时会卡住wxPython的UI线程,进度对话框假死,甚至被系统判定为无响应而中断。
- 无效项干扰:ZIP的
namelist()会包含目录条目(比如subdir/),提取这些目录不仅没用,还会打乱进度计数。
修复后的代码
import wx from zipfile import ZipFile, is_zipfile import os def extract_update(): zip_path = 'wotu.zip' # 先校验ZIP文件有效性 if not is_zipfile(zip_path): wx.MessageBox("无效的ZIP文件!", "错误", wx.OK | wx.ICON_ERROR) return with ZipFile(zip_path, 'r') as f: # 过滤掉updater.exe和目录项,只保留实际文件 files = [file for file in f.namelist() if file != 'updater.exe' and not file.endswith('/')] total_files = len(files) if total_files == 0: wx.MessageBox("没有需要提取的文件!", "提示", wx.OK | wx.ICON_INFORMATION) return # 创建带取消按钮的进度对话框 dlg = wx.ProgressDialog('更新中', '正在提取文件...', total_files, style=wx.PD_APP_MODAL | wx.PD_AUTO_HIDE | wx.PD_CAN_ABORT) progress = 0 keep_running = True for file in files: if not keep_running: break try: target_path = os.path.abspath(file) # 确保目标文件的父目录存在 os.makedirs(os.path.dirname(target_path), exist_ok=True) # 先提取到临时文件,再替换原文件实现覆盖 temp_file = target_path + '.tmp' f.extract(file, os.path.dirname(temp_file)) os.replace(temp_file, target_path) print(f"已提取:{file}") progress += 1 # 更新进度,同时检查用户是否点击取消 keep_running, _ = dlg.Update(progress, f"正在提取:{file}") # 处理UI事件,防止对话框假死 wx.Yield() except Exception as e: print(f"提取{file}失败:{str(e)}") # 询问用户是否继续提取其他文件 keep_running = wx.MessageBox(f"提取{file}失败\n错误信息:{str(e)}\n是否继续提取?", "警告", wx.YES_NO | wx.ICON_WARNING) == wx.YES if not keep_running: break dlg.Destroy() wx.MessageBox("更新完成!", "成功", wx.OK | wx.ICON_INFORMATION) # 主线程调用示例 if __name__ == '__main__': app = wx.App(False) extract_update() app.MainLoop()
关键修改说明
- 强制覆盖文件:通过「临时文件提取+替换」的方式绕开
extract()的覆盖限制,确保旧文件能被替换。 - 过滤无效条目:只处理ZIP中的实际文件,跳过
updater.exe和目录项。 - UI响应优化:加入
wx.Yield()处理UI事件,避免进度对话框假死;同时监听用户的取消操作,允许中途终止。 - 异常容错:捕获提取过程中的所有异常,让用户选择是否继续,避免程序直接崩溃。
内容的提问来源于stack exchange,提问作者Blindgoofball
相关产品推荐
相关产品推荐

