
本文介绍如何使用 Python 的 zipfile 模块批量生成扁平化 ZIP 文件——即每个 ZIP 中只包含目标文本文件本身,不保留原始文件夹路径,适用于学生作业批量打包等场景。
本文介绍如何使用 python 的 `zipfile` 模块批量生成扁平化 zip 文件——即每个 zip 中只包含目标文本文件本身,不保留原始文件夹路径,适用于学生作业批量打包等场景。
在处理多学生提交的作业目录(如 student_1/, student_2/…)时,常见需求是:为每位学生单独生成一个 ZIP 文件,其中仅包含其目录下的 .txt 文件(排除 .html 等非目标文件),且 ZIP 内部不能出现 student_1/ 这样的父级文件夹,所有 .txt 文件应直接位于 ZIP 根层级。
你原代码中调用 zipf.write(file, arcname=file.name) 的思路是正确的,但问题出在两个关键环节:
-
遍历逻辑嵌套不当:
remove_html()中混杂了文件删除、ZIP 创建与路径拼接,易引发路径错误; -
zipCreate()作用域局限:它仅对单个子目录(如student_1/)调用iterdir(),但若该目录下存在嵌套子目录或非文件项,未做类型过滤,可能导致异常或误打包。
下面提供一个健壮、清晰、符合生产实践的解决方案:
✅ 正确实现:扁平化 ZIP 打包(推荐)
import os
import sys
import zipfile
def create_flat_zip_for_subdirs(base_path):
"""
遍历 base_path 下每个子目录,为其创建一个 ZIP 文件,
ZIP 中仅包含该子目录内所有 .txt 文件(不含任何文件夹结构)。
"""
with os.scandir(base_path) as entries:
for entry in entries:
if entry.is_dir(): # 只处理子目录(如 student_1, student_2)
zip_filename = f"{entry.name}.zip"
print(f"正在创建 {zip_filename}...")
with zipfile.ZipFile(zip_filename, 'w', zipfile.ZIP_DEFLATED) as zf:
# 再次扫描该子目录内容
with os.scandir(entry.path) as sub_entries:
for sub_ent in sub_entries:
# 仅添加普通文件,且扩展名为 .txt(可按需改为 not .html)
if sub_ent.is_file() and sub_ent.name.lower().endswith('.txt'):
# 关键:arcname 设为文件名本身,彻底扁平化
zf.write(sub_ent.path, arcname=sub_ent.name)
print(f" → 已添加: {sub_ent.name}")
print(f"✓ {zip_filename} 创建完成\n")
# 使用示例(命令行传参或直接赋值)
if __name__ == "__main__":
# 替换为你的真实路径,例如:assignment1/student_files/
base_dir = sys.argv[1] if len(sys.argv) > 1 else "assignment1/student_files/"
if not os.path.isdir(base_dir):
raise ValueError(f"路径不存在或非目录: {base_dir}")
create_flat_zip_for_subdirs(base_dir)
? 关键要点说明
-
arcname=sub_ent.name是扁平化的灵魂:它强制将文件在 ZIP 中的路径设为纯文件名(如"file1.txt"),而非默认的相对路径(如"student_1/file1.txt"),从而彻底避免 ZIP 内出现文件夹层级。 -
os.scandir()优于os.listdir():它返回DirEntry对象,支持.is_file()/.is_dir()快速判断,避免os.path.isdir()等额外系统调用,性能更优且语义清晰。 -
无需预先删除
.html文件:直接在打包时过滤即可,既安全(保留原始数据)、又高效(减少 I/O 操作)。 -
扩展性提示:如需排除
.html并保留.txt和.py,可将条件改为:if sub_ent.is_file() and sub_ent.name.lower().endswith(('.txt', '.py')) and not sub_ent.name.lower().endswith('.html')
⚠️ 注意事项
- 确保运行脚本的用户对源目录有读取权限,对当前工作目录有写入权限(ZIP 将生成在当前目录);
- 若需将 ZIP 输出到指定目录(如
./zips/),请提前创建并修改zip_filename = os.path.join("./zips", f"{entry.name}.zip"); - Windows 用户注意路径分隔符兼容性:
os.scandir()和zipfile均已自动处理,无需手动替换\。
执行后,你将得到 student_1.zip、student_2.zip … 每个 ZIP 打开后直接显示 file1.txt、file2.txt 等文件,无任何文件夹包裹——完美满足“仅文件、无目录”的核心需求。










