查看: 178|回复: 0

Python自动整理文件夹:pathlib与shutil实现按类型分类

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
在日常开发中,下载文件夹往往堆满各种格式的文件。本文实现一个约120行的Python脚本,通过pathlib遍历目录、shutil.move搬移文件、argparse解析命令行参数,将图片、文档、压缩包等按扩展名自动归类。脚本支持预览模式(--dry-run)和重名保护,避免误移和覆盖。

一、设计思路

这个工具的核心是“查表分类”:拿到文件后缀,去规则表里查它属于哪一类,然后移动到对应子文件夹。分类逻辑全部放在RULES字典中,classify函数只负责查表。

要增加新类别时,只需在RULES里加一行,不需要改动其他代码。

二、需要的前置模块

全部依赖Python标准库,无需安装第三方包。

主要使用以下pathlib技能:

- folder.iterdir():逐个返回文件夹内的文件和子目录
- item.is_dir():判断是否为目录
- item.suffix / item.stem:获取文件后缀(带点)和不带后缀的文件名
- dest.with_name("新名.pdf"):同一目录下构造新文件名

以及shutil.move(source, target),完成跨目录移动。

注意:suffix返回的值自带点号,例如"报告.pdf"的suffix是".pdf"而不是"pdf",后续写规则表时需要对应。

三、代码实现
  1. import argparse
  2. import shutil
  3. from pathlib import Path
  4. RULES = {
  5.     "图片": [".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp"],
  6.     "文档": [".pdf", ".docx", ".doc", ".txt", ".md", ".xlsx", ".pptx"],
  7.     "压缩包": [".zip", ".rar", ".7z", ".tar", ".gz"],
  8.     "安装包": [".exe", ".msi", ".dmg", ".pkg"],
  9.     "视频": [".mp4", ".mkv", ".mov", ".avi"],
  10.     "音频": [".mp3", ".wav", ".flac", ".m4a"],
  11. }
  12. def classify(suffix: str) -> str:
  13.     """根据后缀返回目标文件夹名,未匹配则归入其他"""
  14.     for folder, exts in RULES.items():
  15.         if suffix.lower() in exts:
  16.             return folder
  17.     return "其他"
  18. def unique_path(dest: Path) -> Path:
  19.     """重名保护:已存在时生成 名字(1).ext 等新路径"""
  20.     if not dest.exists():
  21.         return dest
  22.     stem, ext = dest.stem, dest.suffix
  23.     n = 1
  24.     while True:
  25.         candidate = dest.with_name(f"{stem}({n}){ext}")
  26.         if not candidate.exists():
  27.             return candidate
  28.         n += 1
  29. def organize(folder: Path, dry_run: bool = False):
  30.     """遍历当前层文件,分类并移动;dry_run为True时不执行移动"""
  31.     moved = 0
  32.     for item in sorted(folder.iterdir()):
  33.         if item.is_dir() or item.name.startswith("."):
  34.             continue
  35.         target_dir = folder / classify(item.suffix)
  36.         dest = unique_path(target_dir / item.name)
  37.         if dry_run:
  38.             print(f"[预览] {item.name} → {target_dir.name}/")
  39.         else:
  40.             target_dir.mkdir(exist_ok=True)
  41.             shutil.move(str(item), str(dest))
  42.             print(f"已移动:{item.name} → {target_dir.name}/")
  43.         moved += 1
  44.     action = "预览" if dry_run else "整理"
  45.     print(f"—— {action} {moved} 个文件 ——")
  46.     if dry_run:
  47.         print("(预览模式:未做任何改动;去掉 --dry-run 正式执行)")
  48. def main():
  49.     parser = argparse.ArgumentParser(description="下载文件夹整理助手")
  50.     parser.add_argument("folder", nargs="?", default=".",
  51.                         help="要整理的文件夹路径,默认当前目录")
  52.     parser.add_argument("--dry-run", action="store_true",
  53.                         help="预览模式:只显示计划,不动任何文件")
  54.     args = parser.parse_args()
  55.     folder = Path(args.folder).expanduser()
  56.     if not folder.is_dir():
  57.         print(f"文件夹不存在:{folder}")
  58.         return
  59.     organize(folder, dry_run=args.dry_run)
  60. if __name__ == "__main__":
  61.     main()
复制代码

四、关键机制说明

1. 分类规则采用数据驱动。

   分类逻辑集中在RULES字典中,classify函数只是做线性查表。

2. 重名保护使用unique_path函数。

   当目标路径已存在时,依次尝试“文件名(1).ext”、“文件名(2).ext”直到找到可用名称。

   这能防止两个同名文件移动时互相覆盖。

3. 预览与执行分离。

   --dry-run参数让程序只打印计划,不执行shutil.move。

   确认无误后去掉参数再运行,可以避免误操作。

4. 只整理当前层文件。

   遇到子目录直接跳过,不递归处理,也不移动已经生成的分类目录。

   隐藏文件(如.DS_Store、.git)因以点开头被跳过。

五、命令行参数设计

- folder:位置参数,可以传入目标路径,不传时默认整理当前目录。
- --dry-run:开关参数,使用action="store_true",不需要额外值;写了就是True,不写就是False。
- fold.expanduser():将"~"自动展开为用户主目录,兼容Mac和Windows的路径写法。

调用方式:

先预览:
  1. python main.py ~/Downloads --dry-run
复制代码

确认无误后实际执行:
  1. python main.py ~/Downloads
复制代码

路径中含空格时,必须用引号包围:
  1. python main.py "C:\Users\my name\Downloads"
复制代码

六、沙盒验收流程

直接对真实下载目录运行文件操作脚本有风险。建议先建立沙盒验证。

在项目目录下创建sandbox文件夹并填充假文件:
  1. mkdir sandbox && cd sandbox
  2. echo hi > 报告.pdf
  3. echo hi > 神曲.mp3
  4. echo hi > setup.exe
  5. echo hi > IMG_001.jpg
  6. echo hi > 未知.xyz
  7. cd ..
复制代码

Windows下可用 echo hi> 文件名 创建。

然后分别执行:
  1. python main.py sandbox --dry-run
  2. python main.py sandbox
复制代码

检查sandbox分类结果后,再对真实目录先预览后执行。

七、常见错误与解决方案

1. 路径带空格被截断

   命令参数中的空格会被解析为分隔符,导致只识别路径前半段。

   解决办法:给路径加英文双引号。

2. PermissionError: [Errno 13]

   文件正被PDF阅读器、播放器或下载进程占用,无法移动。

   解决办法:关闭相关程序,或者等待下载完成后再执行。

   脚本可以重复运行,因为已经移动的文件不在当前目录中,再次运行时会自动跳过。

3. 文件全部被归入“其他”

   规则表中写的是"pdf"而实际item.suffix返回".pdf",导致查不到。

   解决办法:确认规则表里的扩展名都带前导点。

4. 大写后缀无法识别,如.JPG全进“其他”

   原因是没有调用suffix.lower()统一大小写。

   解决方案:代码中已做lower()处理,如果自己调试,可以创建大写后缀文件在沙盒里测试。

5. 分类文件夹里混入.DS_Store

   macOS会在文件夹中生成以点开头的系统文件,应跳过。

   实际代码中通过item.name.startswith(".")判断,能同时过滤.DS_Store和desktop.ini这类隐藏文件。

6. 直接移动时目标文件重名造成的隐患

   如果不使用unique_path,shutil.move在遇到同名目标时,不同OS下可能直接覆盖或抛错。

   因此所有移动操作都应先经过unique_path处理。

八、适用场景与扩展练习

该脚本适合个人下载目录、临时文件目录的日常整理。

可以继续扩展:

- 在RULES中添加“电子书”或“代码”类别;
- 将默认行为改为只预览,增加--yes参数才真正执行;
- 用脚本批量创建20个假文件,验证每个分类的文件数量;
- 使用Windows任务计划程序或Mac launchd实现定时整理,但务必先在--dry-run模式下确认安全。

这个工具的价值在于安全地改变真实文件系统,分类规则独立、执行动作可预览、重名不覆盖,适合作为文件操作类Python脚本的模板。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-9-4 15:03 , Processed in 0.021189 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部