不能直接用文件名或大小判断重复文件,因为文件名相同不等于内容相同,大小一致也可能是巧合;真正可靠的去重必须基于内容哈希(如sha256),分块读取、二进制模式打开、异常容错,并用字典按哈希值归集路径以识别重复项。

为什么不能直接用文件名或大小判断重复
文件名相同不等于内容相同,大小一致也可能是巧合——比如两个不同图片都恰好是 128KB。真正可靠的去重必须基于内容,而计算特征值(如哈希)是最常用且高效的方式。核心逻辑是:对每个文件读取内容 → 计算固定长度的哈希值(如 sha256)→ 把哈希值当“指纹”比对。
用 hashlib 计算文件 sha256 值的正确姿势
直接 open(file, 'rb').read() 加 hashlib.sha256().update() 看似简单,但大文件会爆内存。必须分块读取,且块大小要合理(太小影响性能,太大无意义)。
推荐做法:
- 使用
hashlib.sha256()实例,避免反复创建对象 - 以
8192字节(8KB)为块大小,平衡 I/O 和 CPU 开销 - 务必用二进制模式
'rb'打开,否则文本模式会破坏二进制文件(如 PDF、图片)的哈希一致性 - 忽略读取异常(如权限不足、符号链接循环),用
try/except跳过,否则整个扫描中断
示例关键代码段:
立即学习“Python免费学习笔记(深入)”;
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
def get_file_hash(filepath):
h = hashlib.sha256()
try:
with open(filepath, 'rb') as f:
while chunk := f.read(8192):
h.update(chunk)
return h.hexdigest()
except (OSError, IOError):
return None
如何高效组织哈希结果并识别重复项
哈希值本身只是字符串,关键是怎么存、怎么查。用字典(dict)最直接:以哈希值为 key,对应文件路径列表为 value。这样一次遍历就能归集所有重复组。
注意点:
- 不要用
list.append()前先检查 key 是否存在——改用defaultdict(list)或setdefault()更简洁安全 - 路径建议用
os.path.abspath()或pathlib.Path.resolve()标准化,避免./a.txt和a.txt被当成两个文件 - 如果文件量极大(百万级),哈希值可考虑只存前 16 字符(
h.hexdigest()[:16])做初筛,再对候选组全哈希比对,节省内存(但有极低碰撞风险)
实际运行时容易被忽略的边界问题
真实环境里,硬链接、软链接、空文件、只读文件、正在写入的文件都会干扰结果。
- 硬链接指向同一 inode,
os.stat().st_ino可快速跳过——相同 inode 的文件无需重复计算哈希 - 软链接默认应跳过(
os.path.islink()),除非你明确想比对目标文件而非链接本身 - 空文件的
sha256是确定值(e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855),但数量多时建议单独处理,避免哈希计算浪费 - 正在被其他进程写入的文件,
hashlib可能读到不完整内容,导致哈希错乱——加os.path.getsize()检查是否稳定,或跳过最近修改的文件
去重不是纯算法问题,而是和文件系统、权限、并发状态强耦合的操作。哪怕哈希逻辑完全正确,漏掉一个 os.path.islink() 判断,就可能把整个目录树的软链接误判为重复内容。

















