应使用hashlib.sha256逐块计算文件全量哈希以准确识别内容重复图片,辅以硬链接检测、图像哈希二次筛选及安全删除校验机制。

用 hashlib 计算文件哈希值来识别重复图片
图片内容相同但文件名、修改时间不同,靠肉眼或 os.path.getsize() 判断极易漏判。必须基于像素内容做一致性校验,最稳妥的是计算整个文件的哈希值(如 sha256)。注意:不能只读取文件头或前几KB,有些重复图可能被轻微重压缩、加了无损元数据,全量读取才能保证准确。
实操建议:
- 用
hashlib.sha256()逐块读取(例如每次8192字节),避免大图一次性加载到内存 - 跳过非图片后缀(如
.txt、.log)可提速,但不要仅依赖后缀——有些图可能没扩展名或被改名,建议先用imghdr.what()或python-magic做二次验证 - 对超大目录(>10万文件),哈希结果建议存入
dict而非list,键为哈希值,值为文件路径列表,查找 O(1)
区分“内容重复”和“硬链接/符号链接”场景
同一张图被硬链接多次时,os.stat().st_ino 相同;若是软链接,则需用 os.path.realpath() 归一化路径。这两类情况哈希值必然一致,但处理策略不同:硬链接本质是同一份数据,删任意一个都会影响其余;软链接则可安全删除源文件外的链接本身。
实操建议:
- 遍历前先调用
os.path.islink()和os.stat()获取st_ino与st_dev,把硬链接归为同一组,只保留其中一个路径 - 若发现某哈希值对应多个路径,且其中存在硬链接关系,优先保留原始路径(
not os.path.islink(path)的那个),其余标记为待删 - 避免在未确认前直接
os.remove()—— 先打印候选列表,加--dry-run参数开关
处理常见误判:缩略图、水印、EXIF 变更
单纯比对完整文件哈希会把带不同 EXIF 信息、不同缩略图、甚至右下角加了半透明水印的图判定为“不重复”,但这往往不是你想要的。如果目标是找“视觉上重复”的图,就得换策略。
实操建议:
- 用
PIL.Image打开后转为灰度 + 统一尺寸(如8x8),再计算平均哈希(imagehash.average_hash()),适合快速粗筛 - 但
imagehash对旋转、裁剪敏感,若需鲁棒性,可用cv2提取 ORB 特征点匹配,不过性能下降明显,仅建议小批量运行 - 生产环境建议分两层:先用文件哈希秒级筛掉真重复项;剩余疑似项再用图像哈希二次判断,并人工抽检几个样本
安全删除前务必确认文件归属和权限
脚本执行 os.remove() 是不可逆操作,尤其当路径含中文、空格、符号或挂载网络盘时,容易因编码或权限问题删错位置,甚至触发系统保护机制。
实操建议:
- 所有待删路径必须先用
os.path.abspath()转成绝对路径,并检查是否在预设根目录内(如if not target_path.startswith(allowed_root): raise ValueError) - 删除前用
os.access(path, os.W_OK)确认写权限,失败则跳过并记录警告 - Windows 下注意
\?前缀对长路径的支持,Linux 下留意 SELinux 上下文是否阻止删除
真正难的不是写对逻辑,而是让脚本在你不在场时,既不误删也不漏删——每一步都要有 fallback 和可观测性。比如哈希冲突概率虽低,但万一遇到,得能从日志里一眼看出是哪两个文件撞了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











