按文件类型(可叠加年份/年月)把下载目录里堆积的文件归入子目录。有一个装在本机的桌面应用版本,能一键整理并常驻监控;这个网页版负责另外半件事 —— 把方案算清楚,把脚本给你。
下载目录是所有人电脑上最先烂掉的那个文件夹:浏览器、聊天软件、邮件附件全往这一个地方倒,几个月后就是几百个平铺的文件——发票 PDF、聊天软件传的截图、装完就没删的安装包、解压过的压缩包、还有一堆看不出是什么的东西。找一份两周前收到的合同,得靠肉眼在滚动条里扫。
手动整理的问题不是「难」,是不可持续:你今天花二十分钟拖成六个文件夹,两周后它又是平的。这套东西把「分类」从一次性劳动变成可重复执行的规则:
| 能力 | 网页版(本页,现在就能点) | 桌面版(装在本机) |
|---|---|---|
| 算归类方案 | 能。拖文件进来即出表,可逐条改目标目录 | 能 |
| 真的移动文件 | 不能 浏览器无写权限 | 能,一键整理 |
| 出可执行脚本 | 能,bash + PowerShell 两版下载 | 不出脚本,它自己就是执行方 |
| 重复文件检测 | 能(同名同大小 + 浏览器自动编号副本) | 不做,只按类型分 |
| 体积大户 / 时间分布 | 能 | 不做 |
| 新文件落地即归位 | 不能,页面关了就没了 | 能,watchdog 常驻监控 |
| 分类子目录 | 后缀 | 数量 |
|---|
| 一键整理 | 点一次按钮,把当前目录里所有平铺的文件按类型分别移进子目录。子目录不存在会自动创建。 |
| 实时监控 | 开启后常驻监听目录,新文件出现即分类归位。会先等待约 0.8 秒再动手,避开浏览器还没下载完就抢走半个文件的情况。可随时停止。 |
| 预演模式 | 勾上「Dry Run」,所有操作只打印不执行——日志里逐行写明「哪个文件会去哪个目录」,一个字节都不会动。第一次用建议先跑这个。 |
| 开机即监控 | 勾上「Auto-Watch on Startup」,以后一打开应用就自动进入监控状态,不用每次手点。 |
| 重名不覆盖 | 目标目录里已有同名文件时,自动改名为 报告 (1).pdf、报告 (2).pdf,绝不覆盖已有文件。 |
| 认得复合后缀 | .tar.gz / .tar.bz2 / .tar.xz 按整体识别为压缩包,重名改名时也保持完整——是 源码 (1).tar.gz,不是 源码.tar (1).gz。 |
| 大小写无关 | 照片.JPG 和 照片.jpg 走同一条规则。 |
| 跳过系统与临时文件 | 按前缀跳过:以 . 开头的隐藏文件、以 ~$ 开头的 Office 临时文件。这两条前缀本身也可以改。 |
| 只碰文件不碰目录 | 目录、以及已经在分类子目录里的文件,一律跳过——重复点「整理」不会把文件越搬越深。 |
| 兜底分类 | 没有任何规则匹配的文件统一进 Others/,不会被留在原地也不会被丢掉。 |
| 7 组内置分类 | Images / Documents / Archives / Installers / Media / Mail / Config,加上兜底的 Others。 |
| 改后缀 | 界面左栏每个分类后面是一行可编辑的后缀列表,直接改,停手约 0.4 秒后自动存盘,不用点保存。少打前面的点也会自动补上。 |
| 增删分类 | 「+ Add Category」新建自己的分类(比如「字体」「电子书」),每行末尾的 ✕ 删掉不想要的。 |
| 换目录 | 默认盯下载目录,也可以改成任何一个文件夹——桌面、截图目录、扫描仪输出目录同样适用。 |
| 配置是一份文本 | 所有设置存成一份 YAML,放在用户配置目录里(~/.config/downloads-organizer/config.yaml),可以直接用编辑器改,也方便在几台机器之间同步。 |
项目是标准 Python 包,需要 Python 3.12 或更高版本。取得源码后在项目根目录安装:
pip install -e ".[dev]"
装完会得到一个可执行命令。下面两条完全等价,都会打开同一个窗口:
downloads-organizer python -m downloads_organizer
--watch 之类的写法,也不要指望它能挂进 cron 之类的定时任务。
不想装东西的话,就在本页导出脚本,回本机跑那一份 —— 效果等价于桌面版的「整理一次」,只是不带常驻监控。
分类逻辑和界面是彻底分开的两层。核心层是一组无状态纯函数:后缀提取(含复合后缀前置匹配)、后缀到分类的查找表构建、前缀跳过判断、以及带防覆盖改名的安全移动。它们不认识窗口、不认识线程,只吃参数吐结果,所以整套分类行为可以脱离图形界面直接被单元测试覆盖——测试用例覆盖了大小写归一、三种 .tar.* 复合后缀、无后缀文件、兜底分类,以及重名改名在普通后缀与复合后缀两种情况下的落点。本页上面那个工具跑的就是这同一套规则的 JavaScript 移植,所以网页算出来的落点和桌面版真跑出来的落点是一致的。移动一律走标准库的移动原语,跨磁盘分区时会自动退化为「复制后删除」。
界面层是 Tkinter 的现代化封装(customtkinter),实时监控由 watchdog 提供文件系统事件。这里有两个必须处理的工程问题:其一,监控回调运行在 watchdog 自己的线程里,直接碰界面控件会引发 Tk 的跨线程崩溃,所以所有日志走一个线程安全队列,由主线程定时取出渲染。其二,浏览器下载会先创建一个零字节的占位文件再慢慢写入,事件一到就搬走会得到半个文件,因此监控回调先短暂等待再复核文件是否仍然存在、是否确实是文件,并且只处理目录顶层的新文件——已经在分类子目录里的不再二次搬运,避免自己触发自己的无限循环。
整理的对象是你这台电脑上那个真实存在的下载目录。浏览器的沙箱模型规定得很死:页面只能拿到用户主动交出来的文件,而且拿到的是一份只读快照——没有写权限、没有重命名权限、没有删除权限,也不能顺着路径往上翻别的目录。这不是本页偷懒,是任何网页都跨不过去的边界,否则随便一个网站都能翻你硬盘。
较新的浏览器有一个 File System Access 接口,可以在用户逐次授权后拿到真正的写权限,但它兼容面窄、每次都要弹授权、且一旦拿到就是能改能删的真权限——为了少建几个文件夹而向一个网页交出下载目录的写权限,这笔账不划算。所以本页明确不走那条路。
退一万步,「上传到服务器再整理」更不该做:那意味着把整个下载目录复制一份到别人机器上。所以这里的分工就是最诚实的那种——网页负责算和看,执行留在你自己手上,形式是一份你能逐行读懂、默认还不生效的脚本。