跳至正文

用Python写了个文件自动整理脚本,桌面终于不乱套了

我的桌面 download 文件夹,已经变成了黑洞。

下过来的 PDF、图片、压缩包、安装包,全堆在一块。每次找东西都要翻半天,最后实在忍不了,写了个 Python 脚本自动归类。折腾一晚上,终于清爽了。

痛点:不是不想整理,是整理一次马上又乱

我之前试过手动建文件夹:

Downloads/
  ├── 文档/
  ├── 图片/
  ├── 软件/
  └── 压缩包/

配图1

理完挺舒服,但不超过三天,根目录又是一堆新文件。人都有惰性,下载完顺手就关了保存对话框,根本不想选目录。

核心问题不是”不会整理”,是”每次都要做选择”。

所以我要的不是手动分类,而是让脚本在后台自动把新文件搬进对应文件夹。

方案:按扩展名自动分类 + 按日期归档

脚本思路很简单:

  • 扫描 `~/Downloads` 根目录下的文件
  • 根据扩展名判断类型
  • 移动到对应的分类目录
  • 每个分类目录下再按月归档

代码如下:

#!/usr/bin/env python3
"""
文件自动整理脚本
把 ~/Downloads 根目录的文件按扩展名分类,并按月份归档。
"""
import os
import shutil
from datetime import datetime
from pathlib import Path

DOWNLOADS = Path.home() / "Downloads"

# 扩展名 -> 分类目录
CATEGORY_MAP = {
    "文档": [".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".txt", ".md"],
    "图片": [".jpg", ".jpeg", ".png", ".gif", ".webp", ".svg", ".bmp"],
    "软件": [".dmg", ".pkg", ".exe", ".msi", ".app"],
    "压缩包": [".zip", ".rar", ".7z", ".tar", ".gz", ".bz2"],
    "视频": [".mp4", ".mov", ".avi", ".mkv", ".flv"],
    "音频": [".mp3", ".wav", ".flac", ".aac", ".m4a"],
    "代码": [".py", ".js", ".html", ".css", ".json", ".yaml", ".yml", ".sh"],
}

# 反向映射:扩展名 -> 分类
EXT_TO_CATEGORY = {}
for category, exts in CATEGORY_MAP.items():
    for ext in exts:
        EXT_TO_CATEGORY[ext.lower()] = category


def get_category(path: Path) -> str:
    ext = path.suffix.lower()
    return EXT_TO_CATEGORY.get(ext, "其他")


def organize():
    moved = 0
    for item in DOWNLOADS.iterdir():
        if not item.is_file():
            continue
        # 跳过隐藏文件和本脚本
        if item.name.startswith(".") or item.name == "organize.py":
            continue

        category = get_category(item)
        month = datetime.fromtimestamp(item.stat().st_mtime).strftime("%Y-%m")

        target_dir = DOWNLOADS / category / month
        target_dir.mkdir(parents=True, exist_ok=True)

        target = target_dir / item.name
        # 处理重名
        counter = 1
        stem = target.stem
        suffix = target.suffix
        while target.exists():
            target = target_dir / f"{stem}_{counter}{suffix}"
            counter += 1

        shutil.move(str(item), str(target))
        print(f"Moved: {item.name} -> {category}/{month}/")
        moved += 1

    print(f"n整理完成,共移动 {moved} 个文件。")


if __name__ == "__main__":
    organize()

配图2

跑一次,把我桌面 200 多个文件全归好了。根目录只剩几个分类文件夹,看着顺眼多了。

踩坑一:隐藏文件和脚本自身被误移动

第一次跑的时候,脚本把 `.DS_Store` 也当成普通文件移走了。 macOS 用户都知道这玩意儿有多烦,每个文件夹一个,移动它没问题,但它会污染分类目录。

解决办法:判断文件名以 `.` 开头就跳过。

另外脚本自身如果也放在 `Downloads` 里,会被自己移走。加一行判断跳过 `organize.py`。

踩坑二:重名文件直接覆盖

同一批下载里经常会有同名文件,比如 `image.png`、`image (1).png`。`shutil.move` 默认会直接覆盖目标文件,我差点把几个重要文件搞丢。

解决办法:在移动前检查目标是否存在,存在就加 `_1`、`_2` 后缀,直到不冲突。

counter = 1
stem = target.stem
suffix = target.suffix
while target.exists():
    target = target_dir / f"{stem}_{counter}{suffix}"
    counter += 1

配图3

这个逻辑虽然简单,但没加之前就是隐患。

踩坑三:分类目录本身被扫进去

脚本跑过一次后,`Downloads` 下已经有了 `文档/`、`图片/` 这些分类目录。如果脚本写得不严谨,下次运行时可能把这些目录也当成”待整理的文件”处理。

我的处理方式是只处理 `is_file()`,目录直接跳过。这样分类目录不会再被碰。

踩坑四:扩展名大小写不一致

macOS 默认不区分大小写,但 Python 的 `path.suffix` 是区分大小写的。`.JPG` 和 `.jpg` 如果不做 `.lower()`,会被分到”其他”里。

解决办法:所有扩展名比较前都转成小写。

踩坑五:按月归档还是按类型平铺?

一开始我纠结分类目录下要不要再按月份分。有人可能喜欢所有 PDF 都在一起,找起来方便。

但试了一下,单一目录文件太多时 Finder 会卡。按月归档后,每个目录文件数可控,找最近下载的东西也很快。

最终结构:

Downloads/
  ├── 文档/
  │   ├── 2026-07/
  │   └── 2026-06/
  ├── 图片/
  │   ├── 2026-07/
  │   └── 2026-06/
  └── ...

进阶:配合 crontab 定时执行

手动跑一次只是治标不治本。我把它加到 crontab,每 15 分钟自动执行一次:

*/15 * * * * /Users/mac/.pyenv/shims/python3 /Users/mac/Downloads/organize.py >> /tmp/organize.log 2>&1

这样下载完不用管,过一会儿文件自己就归位了。

总结

这个脚本技术含量不高,但解决的是一个真实痛点:**重复决策带来的消耗**。

踩坑经验:

  • 隐藏文件和脚本自身要跳过,避免自毁。
  • 移动文件前先处理重名,防止覆盖。
  • 只处理文件不处理目录,避免分类目录被误伤。
  • 扩展名统一转小写,兼容 macOS 和 Windows 习惯。
  • 单一目录文件过多会卡,建议按月再细分。

现在我的 Downloads 根目录每天都是干净的。省下的时间不多,但心情好了很多。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注