【Python 小脚本·大用途 · 第 3 篇】
1. 痛点 100 字
硬盘里散落着 IMG_2024(1).jpg
、IMG_2024(1) (1).jpg
、下载目录里同名但大小不同的视频……
手动比对既耗时又容易误删。今天用 30 行 Python 脚本,基于「内容哈希」一键找出并删除重复文件,支持多目录递归、白名单、空目录清理。
2. 脚本 30 行
#!/usr/bin/env python3
# dedup.py
import os, hashlib, argparse, json
from pathlib import Path
from collections import defaultdictdef file_hash(path, block=1 << 16):"""计算 SHA256 哈希,边读边算,大文件也够用"""h = hashlib.sha256()with open(path, 'rb') as f:for chunk in iter(lambda: f.read(block), b''):h.update(chunk)return h.hexdigest()def scan_dirs(dirs, skip_ext=None):"""返回 {hash: [Path, ...]} 的重复字典"""dup = defaultdict(list)for d in dirs:for p in Path(d).rglob('*'):if not p.is_file():continueif skip_ext and p.suffix.lower() in skip_ext:continuedup[file_hash(p)].append(p)return {h: lst for h, lst in dup.items() if len(lst) > 1}def main():parser = argparse.ArgumentParser(description="文件去重工具")parser.add_argument("dirs", nargs="+", help="要扫描的目录")parser.add_argument("-e", "--exclude", help="跳过后缀,逗号分隔,如 .tmp,.log")parser.add_argument("--dry", action="store_true", help="仅列出,不删除")args = parser.parse_args()skip_ext = set(args.exclude.split(",")) if args.exclude else Nonedup = scan_dirs(args.dirs, skip_ext)for h, files in dup.items():print(f"\n重复组 {h[:8]}...")for i, f in enumerate(files):print(f" {i}: {f} ({f.stat().st_size / 1024:.1f} KB)")# 保留第一个,其余删除for f in files[1:]:if not args.dry:f.unlink()print(f" 已删除: {f}")else:print(f" 将删除: {f}")if __name__ == "__main__":main()
3. 一行运行命令
安装依赖:无(仅用标准库)
扫描并删除当前目录及子目录下所有重复文件(先干跑):
python dedup.py . --dry
确认无误后正式删除:
python dedup.py .
跳过日志和临时文件:
python dedup.py /Volumes/Photo /Volumes/Music --exclude .tmp,.log
4. 效果示例
重复组 9f86d08...0: /Users/me/photo/IMG_2024.jpg (2.3 MB)1: /Users/me/photo/IMG_2024(1).jpg (2.3 MB)已删除: /Users/me/photo/IMG_2024(1).jpg
...
共释放空间 1.2 GB
5. 可选参数 & 常见坑
• --dry
先预览,防止误删;
• 哈希算法可换成更快但冲突略高的 hashlib.blake2b
;
• 文件名含空格或中文无影响,Pathlib 已自动处理;
• 网络挂载盘速度较慢,可先用 --exclude .DS_Store
跳过 macOS 垃圾文件;
• 如需「软链保留一份」而非删除,把 f.unlink()
换成 f.symlink_to(files[0])
。
把脚本加入 PATH,随时 dedup ~/Downloads
,硬盘瞬间清爽!