用hashlib计算文件哈希值需分块读取(如8192字节)以避免内存溢出,优先按文件大小预筛再哈希,跳过权限错误与已删除文件,Windows下用os.path.samefile()剔除硬链接冗余。

用 hashlib 计算文件哈希值再分组
直接比对文件内容太慢,必须靠哈希跳过逐字节比较。核心思路是:遍历目录 → 对每个文件计算 sha256(或 md5)→ 把相同哈希值的文件路径归到同一组。注意别用 md5 做唯一性断言,碰撞概率虽低但非零;生产环境建议用 sha256。
关键细节:
- 大文件不能一次性
read()进内存,得用分块读取(比如每次8192字节) - 空文件哈希值一致,要单独处理,否则所有空文件会被误判为“重复”
- 符号链接默认不应跟随,否则可能重复计入或引发权限错误,需显式控制
follow_symlinks=False
跳过大小不同的文件,先做快速预筛
哈希计算仍是瓶颈,尤其面对上万个小文件。实际中 99% 的不同文件大小就不同,所以先按 os.path.getsize() 分组,只对同尺寸文件集计算哈希——能省下大量 I/O 和 CPU。
示例逻辑片段:
立即学习“Python免费学习笔记(深入)”;
from collections import defaultdict
size_map = defaultdict(list)
for path in all_files:
size = os.path.getsize(path)
size_map[size].append(path)
<p>duplicates = {}
for size, paths in size_map.items():
if len(paths) < 2:
continue
hash_map = defaultdict(list)
for path in paths:
h = compute_hash(path) # 分块计算 sha256
hash_map[h].append(path)
for h, paths_in_hash in hash_map.items():
if len(paths_in_hash) > 1:
duplicates[h] = paths_in_hash
遇到 PermissionError 或 UnicodeDecodeError 怎么办
真实目录常含系统文件、临时文件或编码异常路径,硬抛错会中断整个扫描。必须捕获并跳过:
-
PermissionError:跳过,不记录也不报错(比如/proc下的文件) -
OSError(含FileNotFoundError):说明文件已被删除或移动,直接忽略 -
UnicodeDecodeError不会出现在二进制哈希计算中——因为open(..., 'rb')绕过了文本解码,这点很多人误踩
务必用 try/except 包住单个文件的哈希计算,而不是整个循环。
Windows 下路径大小写和硬链接的干扰
Windows 默认不区分路径大小写,但 os.path.samefile() 可检测是否指向同一 inode(NTFS 支持硬链接)。如果两个路径 os.path.samefile(a, b) 返回 True,它们本质是同一个文件,不该算作“重复”——应从结果中剔除。
操作建议:
- 对每组疑似重复文件,先两两调用
os.path.samefile() - 若返回
True,保留其中一个路径,其余标记为“硬链接冗余”而非“内容重复” - 注意:该函数在 Windows 上对符号链接返回
False,仅对硬链接有效
真正难搞的是跨卷硬链接或 NTFS 重解析点,这种场景下 samefile 失效,只能依赖哈希——但此时用户其实更需要的是“找出所有指向相同数据的路径”,而非单纯“内容重复”。问题边界得提前跟使用者对齐。


















