Python zipfile压缩程序偶发自引用死循环导致体积无限增长问题
问题根因
核心逻辑漏洞是你把生成的压缩包直接放在了待压缩的目标目录下,结合两个场景触发偶发异常:
- 首次运行后目标目录下已经存在同名的
myzipfile.zip文件,再次运行时_walk遍历会将历史压缩包纳入待压缩列表,新生成的压缩包会包含旧包,多次运行后体积会指数级膨胀 - 当待压缩目录文件数量极多、遍历耗时较长时,部分操作系统的文件写入缓存机制可能会让
ZipFile初始化创建的空压缩包文件提前被目录遍历捕获,纳入待写入列表,后续写入时就会出现边读压缩包、边往压缩包里写的死循环,体积无限增长。
另外代码中_walk函数没有过滤特殊文件、也没有排除目标压缩包的逻辑,是触发问题的直接诱因。
修复方案
- 优先将生成的压缩包输出路径改到待压缩目录之外,从根源避免被遍历到;如果必须放在当前目录,就遍历的时候主动排除目标压缩包文件
- 调整逻辑顺序,先确认压缩包的绝对路径,执行目录遍历时直接过滤该文件
- 删除冗余的
zipf.close()调用,with上下文管理器会自动关闭压缩包文件
修复后代码如下:
import tkinter as tk from tkinter import filedialog from pathlib import Path import zipfile import os root = tk.Tk() root.withdraw() file_path = filedialog.askdirectory() # 直接用绝对路径处理,避免工作目录切换带来的混乱 target_dir = Path(file_path).resolve() def _walk(path: Path, exclude_file: Path = None) -> list: all_files = [] for x in path.iterdir(): # 遍历过程主动排除目标压缩包文件 if exclude_file is not None and x.resolve() == exclude_file: continue if x.is_dir(): all_files.extend(_walk(x, exclude_file)) else: all_files.append(x) return all_files def zip_files(path: Path, archive_name: str): # 先拿到压缩包的绝对路径,如需放到待压缩目录外可改为 archive_path = path.parent / archive_name archive_path = (path / archive_name).resolve() all_files = _walk(path, exclude_file=archive_path) with zipfile.ZipFile(archive_path, 'w', zipfile.ZIP_DEFLATED) as zipf: for f in all_files: # 指定arcname为相对路径,避免压缩包里出现多层冗余的绝对目录结构 zipf.write(f, arcname=f.relative_to(path)) def zip_this_folder(): print('compressing...') zip_files(target_dir, 'myzipfile.zip') print('...compression done!') if __name__ == "__main__": zip_this_folder()
内容的提问来源于stack exchange,提问作者MM-13
相关产品推荐
相关产品推荐

