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脚本的模板。
Re: Python自动整理文件夹:pathlib与shutil实现按类型分类
这个脚本写得很实用,尤其喜欢查表分类的思路,想加规则直接在 RULES 里加一行就行,扩展起来特别方便。预览模式和重名保护也很贴心,实际用的时候能避免很多“手滑”的情况。一个小建议:分类的时候只处理了当前层的文件,如果下载文件夹里有子文件夹,可能需要额外处理一下;不过作为轻量工具已经够用了。Re: Python自动整理文件夹:pathlib与shutil实现按类型分类
代码写得很干净,pathlib 加 shutil 的组合确实比传统 os.path 好读不少。分类规则表的设计也方便扩展,加个后缀就能用。 有个小建议:文件重名时 unique_path 只考虑了目标文件是否存在,但如果分类文件夹里已经有一个同名的 **目录**(比如有人手动建了一个叫“报告.pdf”的文件夹),那 unique_path 会把它当成已存在文件处理,生成“报告(1).pdf”,倒是不会覆盖,不过逻辑上可能想区分一下文件和目录的情况。 另外想确认一下:脚本只处理当前层文件,不会递归进入子文件夹吧?如果下载文件夹里本身就有“文档”“图片”这些历史分类目录,再次运行会跳过它们,这点倒是没问题。但对于之前没分类、嵌套在子文件夹里的文件,目前好像不会管到。日常用得不多的话其实也够用,但如果想要“清一遍整个文件夹”,可以考虑加个 --recursive 参数。 整体很实用,我准备直接拿去整理一下我的下载目录了,感谢分享。Re: Python自动整理文件夹:pathlib与shutil实现按类型分类
这个脚本思路很清晰,正好解决了我的下载目录乱糟糟的问题。特别是 `--dry-run` 预览模式,对第一次使用的人来说很友好,可以先看看效果再真正执行,避免误移文件。 有一点想请教:目前 `organize` 只遍历当前一层目录,如果下载文件夹里有子目录,脚本会跳过它们。后续有没有考虑加上递归扫描子目录的功能?比如图片库套娃文件夹比较多,能一并归类就完美了。 另外 `RULES` 字典用列表存后缀,查表时是线性遍历,后缀多的时候效率略低。如果改成 `{后缀: 类别}` 的反向字典,`classify` 直接查一次就能返回结果,代码也更简洁。不过对于120行的工具脚本来说,现在的写法胜在直观易懂,方便大家按自己的需求增删类别。 整体很实用,先收藏了,找个时间跑一下试试。
页:
[1]