
本文介绍如何使用 Python 的 zipfile 模块批量生成扁平化 ZIP 文件——即 ZIP 中直接存放 .txt 文件,不保留原始子目录路径,同时跳过 .html 等非目标文件,无需预先删除源文件。
本文介绍如何使用 python 的 `zipfile` 模块批量生成扁平化 zip 文件——即 zip 中直接存放 `.txt` 文件,不保留原始子目录路径,同时跳过 `.html` 等非目标文件,无需预先删除源文件。
在处理学生作业等多级目录场景时,常见需求是:对每个子目录(如 student_1/, student_2/)分别打包其中的 .txt 文件,但ZIP 内部不能出现任何文件夹层级——所有 .txt 文件应直接位于 ZIP 根目录下(例如 student_1.zip 解压后应直接看到 file1.txt, file2.txt,而非 student_1/file1.txt)。这要求在调用 zipfile.ZipFile.write() 时,显式指定 arcname 参数为纯文件名,彻底剥离路径信息。
以下是一个健壮、清晰且符合最佳实践的实现:
import os
import sys
import zipfile
def create_flat_zip_per_subdir(base_path):
"""
遍历 base_path 下每个子目录,为每个子目录创建一个 ZIP 文件,
ZIP 中仅包含该子目录下的 .txt 文件(不含 .html),且无目录结构。
"""
with os.scandir(base_path) as base_iter:
for entry in base_iter:
if entry.is_dir():
zip_filename = f"{entry.name}.zip"
print(f"Creating {zip_filename}...")
with zipfile.ZipFile(zip_filename, 'w', zipfile.ZIP_DEFLATED) as zf:
with os.scandir(entry.path) as sub_iter:
for file_entry in sub_iter:
# 仅处理普通文件,且扩展名为 .txt(可按需调整逻辑,如排除 .html)
if (file_entry.is_file()
and file_entry.name.lower().endswith('.txt')
and not file_entry.name.lower().endswith('.html')):
# 关键:arcname=file_entry.name 实现“扁平化”——忽略路径,只存文件名
zf.write(file_entry.path, arcname=file_entry.name)
print(f"✓ {zip_filename} created with {len([f for f in os.scandir(entry.path) if f.is_file() and f.name.lower().endswith('.txt') and not f.name.lower().endswith('.html')])} text files.")
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python zip_flat.py <base_directory>")
sys.exit(1)
base_dir = sys.argv[1]
if not os.path.isdir(base_dir):
print(f"Error: '{base_dir}' is not a valid directory.")
sys.exit(1)
create_flat_zip_per_subdir(base_dir)</base_directory>
✅ 关键要点说明:
- 使用
os.scandir()替代os.listdir()+os.path.join(),性能更优且语义更清晰; -
zipf.write(path, arcname=name)中的arcname参数决定 ZIP 内部显示的路径——设为file_entry.name即强制扁平化; -
无需预先删除
.html文件:过滤逻辑在压缩时完成,保护原始数据安全; - 支持大小写不敏感匹配(
.lower()),避免因File.HTML被遗漏; - 添加了输入校验与进度提示,便于调试和生产使用。
⚠️ 注意事项:
- 若子目录中存在同名
.txt文件(如student_1/file1.txt和student_2/file1.txt),它们将分别进入不同 ZIP,互不影响; - ZIP 文件默认生成在当前工作目录下,如需指定输出路径,可修改
zip_filename = os.path.join(output_dir, f"{entry.name}.zip"); - 如需支持更多格式(如
.py,.csv),只需扩展endswith()条件,例如file_entry.name.lower().split('.')[-1] in {'txt', 'py', 'csv'}。
通过此方案,你将得到一组真正“无目录”的 ZIP 文件,结构简洁、语义明确,完全契合自动化归档与后续批处理需求。










