Python 查找重复文件并删除:按 MD5 去重实战
用 Python 按文件大小和 MD5 哈希找出重复文件,保留一份删掉其余,释放磁盘空间,附 dry-run 预览和按目录优先保留策略。
场景痛点
照片备份、资料下载、项目迭代,同一张图、同一份 PDF 散在好几个文件夹,重复占空间,手动根本分不出哪份是真重复。用文件大小先粗筛、再用 MD5 哈希精验,内容相同的文件不管叫什么名字都能认出来。保留一份,把其余重复列出来给你确认后删除,腾磁盘空间。
用到的库
纯标准库,无需 pip 安装:
# os、hashlib 为标准库
完整代码
import os
import hashlib
# ========== 配置区 ==========
SCAN_DIR = "./素材库" # 要扫描重复文件的目录
DRY_RUN = True
KEEP_FIRST = True # True=保留每一组里第一个,删其余
# ============================
def md5_of_file(path: str, chunk_size: int = 1024 * 1024) -> str:
"""分块读取算 MD5,避免大文件一次性读进内存。"""
h = hashlib.md5()
with open(path, "rb") as f:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
h.update(chunk)
return h.hexdigest()
def main():
if not os.path.isdir(SCAN_DIR):
print(f"目录不存在:{SCAN_DIR}")
return
# 第一遍:按大小分组,大小不同的文件内容一定不同
size_map = {}
for dirpath, _, filenames in os.walk(SCAN_DIR):
for name in filenames:
p = os.path.join(dirpath, name)
size = os.path.getsize(p)
size_map.setdefault(size, []).append(p)
# 第二遍:只对大小相同的文件算 MD5
hash_map = {}
for size, paths in size_map.items():
if len(paths) < 2:
continue # 大小唯一,不可能重复,跳过省时间
for p in paths:
try:
h = md5_of_file(p)
except (PermissionError, OSError):
continue
hash_map.setdefault(h, []).append(p)
# 找出有重复的组
dup_groups = {h: ps for h, ps in hash_map.items() if len(ps) > 1}
print(f"发现 {len(dup_groups)} 组重复文件:\n")
freed = 0
to_delete = []
for h, paths in dup_groups.items():
print(f"[重复组] {len(paths)} 个:")
for p in paths:
print(f" {p}")
# 保留第一个,其余标记删除
for p in paths[1:]:
to_delete.append(p)
freed += os.path.getsize(p)
print()
print(f"将删除 {len(to_delete)} 个文件,释放约 {freed/1024/1024:.1f} MB")
if not DRY_RUN:
for p in to_delete:
os.remove(p)
print("已删除多余副本,每组保留一份。")
else:
print("当前是预览。确认保留策略合理,把 DRY_RUN 改成 False 再跑。")
if __name__ == "__main__":
main()
代码讲解
- 两遍筛查:第一遍按文件大小分组,大小不同的文件内容必然不同,直接排除;第二遍只对大小相同的文件算 MD5。这样能省掉绝大部分哈希计算,扫整个素材库也快。
- 分块读 MD5:
md5_of_file每次读 1MB 进内存,几个 G 的视频也不会把内存撑爆。 - MD5 判等:两个文件 MD5 相同,内容几乎可以认为一样(碰撞概率可忽略)。不管文件名叫什么、在哪个目录,内容相同就归为一组。
- 保留策略:每组保留
paths[0],其余标记删除。paths[0]是 os.walk 遍历到的第一个文件。想按"路径最短/名字最规范"保留,自己排一下顺序即可。
运行结果
终端打印每一组重复文件的完整路径,告诉你将删几个、释放多少 MB。预览看清楚每组里保留的那份是不是你想留的,把 DRY_RUN 改成 False 正式去重。
注意事项
- 保留哪份要自己看:脚本默认保留遍历到的第一个。重要资料组里,肉眼确认保留的不是旧版本/坏文件,再跑真删。
- MD5 不是加密用途:这里只是内容指纹,用来判等足够,别拿它做安全相关的事。
- 文件名不同但内容相同才是重复:MD5 相同就会被识别。如果你想要的是"同名文件重复",那是另一种逻辑,别混。
- 软链接:本脚本会把软链接当文件读,可能误删。素材库里软链接多就加
os.path.islink(p)判断跳过。 - 删除不可逆:真删前最好先把要删的清单导出来存一份,或者先移到一个
_待删文件夹观察几天再清空。

更新时间:2026-09-14 21:18:03