脚本专家 发表于 2026-9-4 14:00:00

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

在日常开发中,下载文件夹往往堆满各种格式的文件。本文实现一个约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",后续写规则表时需要对应。

三、代码实现


import argparse
import shutil
from pathlib import Path

RULES = {
    "图片": [".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp"],
    "文档": [".pdf", ".docx", ".doc", ".txt", ".md", ".xlsx", ".pptx"],
    "压缩包": [".zip", ".rar", ".7z", ".tar", ".gz"],
    "安装包": [".exe", ".msi", ".dmg", ".pkg"],
    "视频": [".mp4", ".mkv", ".mov", ".avi"],
    "音频": [".mp3", ".wav", ".flac", ".m4a"],
}

def classify(suffix: str) -> str:
    """根据后缀返回目标文件夹名,未匹配则归入其他"""
    for folder, exts in RULES.items():
      if suffix.lower() in exts:
            return folder
    return "其他"

def unique_path(dest: Path) -> Path:
    """重名保护:已存在时生成 名字(1).ext 等新路径"""
    if not dest.exists():
      return dest
    stem, ext = dest.stem, dest.suffix
    n = 1
    while True:
      candidate = dest.with_name(f"{stem}({n}){ext}")
      if not candidate.exists():
            return candidate
      n += 1

def organize(folder: Path, dry_run: bool = False):
    """遍历当前层文件,分类并移动;dry_run为True时不执行移动"""
    moved = 0
    for item in sorted(folder.iterdir()):
      if item.is_dir() or item.name.startswith("."):
            continue
      target_dir = folder / classify(item.suffix)
      dest = unique_path(target_dir / item.name)

      if dry_run:
            print(f"[预览] {item.name} → {target_dir.name}/")
      else:
            target_dir.mkdir(exist_ok=True)
            shutil.move(str(item), str(dest))
            print(f"已移动:{item.name} → {target_dir.name}/")
      moved += 1

    action = "预览" if dry_run else "整理"
    print(f"—— {action} {moved} 个文件 ——")
    if dry_run:
      print("(预览模式:未做任何改动;去掉 --dry-run 正式执行)")

def main():
    parser = argparse.ArgumentParser(description="下载文件夹整理助手")
    parser.add_argument("folder", nargs="?", default=".",
                        help="要整理的文件夹路径,默认当前目录")
    parser.add_argument("--dry-run", action="store_true",
                        help="预览模式:只显示计划,不动任何文件")
    args = parser.parse_args()

    folder = Path(args.folder).expanduser()
    if not folder.is_dir():
      print(f"文件夹不存在:{folder}")
      return
    organize(folder, dry_run=args.dry_run)

if __name__ == "__main__":
    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的路径写法。

调用方式:

先预览:

python main.py ~/Downloads --dry-run


确认无误后实际执行:

python main.py ~/Downloads


路径中含空格时,必须用引号包围:


python main.py "C:\Users\my name\Downloads"


六、沙盒验收流程

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

在项目目录下创建sandbox文件夹并填充假文件:


mkdir sandbox && cd sandbox
echo hi > 报告.pdf
echo hi > 神曲.mp3
echo hi > setup.exe
echo hi > IMG_001.jpg
echo hi > 未知.xyz
cd ..


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

然后分别执行:


python main.py sandbox --dry-run
python main.py sandbox


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

七、常见错误与解决方案

1. 路径带空格被截断

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

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

2. PermissionError:

   文件正被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脚本的模板。

热心网友1 发表于 2026-9-4 19:00:00

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

这个脚本写得很实用,尤其喜欢查表分类的思路,想加规则直接在 RULES 里加一行就行,扩展起来特别方便。预览模式和重名保护也很贴心,实际用的时候能避免很多“手滑”的情况。一个小建议:分类的时候只处理了当前层的文件,如果下载文件夹里有子文件夹,可能需要额外处理一下;不过作为轻量工具已经够用了。

热心网友1 发表于 2026-9-4 19:00:00

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

代码写得很干净,pathlib 加 shutil 的组合确实比传统 os.path 好读不少。分类规则表的设计也方便扩展,加个后缀就能用。 有个小建议:文件重名时 unique_path 只考虑了目标文件是否存在,但如果分类文件夹里已经有一个同名的 **目录**(比如有人手动建了一个叫“报告.pdf”的文件夹),那 unique_path 会把它当成已存在文件处理,生成“报告(1).pdf”,倒是不会覆盖,不过逻辑上可能想区分一下文件和目录的情况。 另外想确认一下:脚本只处理当前层文件,不会递归进入子文件夹吧?如果下载文件夹里本身就有“文档”“图片”这些历史分类目录,再次运行会跳过它们,这点倒是没问题。但对于之前没分类、嵌套在子文件夹里的文件,目前好像不会管到。日常用得不多的话其实也够用,但如果想要“清一遍整个文件夹”,可以考虑加个 --recursive 参数。 整体很实用,我准备直接拿去整理一下我的下载目录了,感谢分享。

热心网友6 发表于 2026-9-4 19:10:00

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

这个脚本思路很清晰,正好解决了我的下载目录乱糟糟的问题。特别是 `--dry-run` 预览模式,对第一次使用的人来说很友好,可以先看看效果再真正执行,避免误移文件。 有一点想请教:目前 `organize` 只遍历当前一层目录,如果下载文件夹里有子目录,脚本会跳过它们。后续有没有考虑加上递归扫描子目录的功能?比如图片库套娃文件夹比较多,能一并归类就完美了。 另外 `RULES` 字典用列表存后缀,查表时是线性遍历,后缀多的时候效率略低。如果改成 `{后缀: 类别}` 的反向字典,`classify` 直接查一次就能返回结果,代码也更简洁。不过对于120行的工具脚本来说,现在的写法胜在直观易懂,方便大家按自己的需求增删类别。 整体很实用,先收藏了,找个时间跑一下试试。
页: [1]
查看完整版本: Python自动整理文件夹:pathlib与shutil实现按类型分类