先按文件大小分组再计算md5可提速5–10倍;用os.path.getsize()快速筛选,仅对同大小文件组计算哈希;分块读取防内存溢出,需二进制模式+try/except;用defaultdict(list)高效分组,注意硬链接与符号链接处理。

用 os.path.getsize() 快速筛掉大小不同的文件
文件大小不同,MD5 一定不同,所以先按大小分组能省下大量哈希计算。尤其处理上万文件时,这步能提速 5–10 倍。
常见错误是直接对所有文件跑 hashlib.md5(),结果卡在 I/O 上,还容易被误判(比如大文件读到一半出错没捕获)。
- 只对同大小的文件组再比 MD5,组内文件数通常 ≤ 5,效率高
- 注意
os.path.getsize()返回字节,别和 KB/MB 混用;路径含中文或特殊符号时,确保用str或pathlib.Path处理,避免UnicodeEncodeError - 空文件大小都是 0,但内容可能不同(比如一个真空,一个含 BOM),所以大小相同时仍需哈希验证
用 hashlib.md5() 分块读取防内存爆掉
直接 open(...).read() 读 GB 级文件会把整个文件塞进内存,Python 进程可能被系统 kill,或者拖慢整台机器。
正确做法是分块读——每次只读 8192 字节(或 64KB),喂给 md5.update() 累积哈希值。
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
- 块大小选
8192是平衡 I/O 和 CPU,太小(如 1024)调用太频繁,太大(如 1MB)对小文件不友好 - 必须用二进制模式打开:
open(path, "rb"),否则文本模式会解码失败或跳过某些字节 - 别漏掉
try/except:权限不足、文件被占用、路径不存在都会抛OSError,跳过即可,别让整个程序崩
with open(path, "rb") as f:
md5 = hashlib.md5()
for chunk in iter(lambda: f.read(8192), b""):
md5.update(chunk)
return md5.hexdigest()
用 collections.defaultdict(list) 聚合同大小或同哈希的文件
不用手动判断 key 是否存在,也别用 dict.setdefault() 写三行——defaultdict(list) 一行搞定分组逻辑,代码干净还不易错。
场景:你拿到 1000 个文件,想找出哪些路径对应同一个 MD5,这时候键是 file_size 或 md5_hex,值是路径列表。
- 如果按大小分组后发现某组只有 1 个文件,直接跳过 MD5 计算
- 哈希值做字典 key 时,确保用
.hexdigest()(字符串),别用.digest()(bytes),后者不可哈希还会报TypeError - 路径建议用
os.path.abspath(path)归一化,避免./a.txt和a.txt被当成两个不同文件
注意硬链接与符号链接的干扰
Linux/macOS 下,硬链接指向同一 inode,os.path.getsize() 和 MD5 完全一致,但它们是“同一个文件”,删一个另一个就没了——这不是重复,是镜像。
而符号链接若指向不同目标,大小和 MD5 可能撞车,但实际内容无关。不处理的话,你会误删不该删的文件。
- 用
os.stat(path).st_ino和os.stat(path).st_dev判断是否为同一硬链接(同设备 + 同 inode) - 用
os.path.islink(path)排除符号链接,或用os.path.realpath(path)解析后再比(视需求而定) - Windows 没硬链接(除非管理员启用了开发者模式),但有 NTFS 符号链接和交接点(junction),
os.path.islink()在 Python 3.8+ 才稳定支持
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










