文件重复判定采用分层验证:先比大小和修改时间快速筛选;再分块计算sha-256哈希值;最后比对哈希指纹;需统一读取方式、避免bom干扰、确保算法与缓冲策略一致。
用输入流顺序比对来判定文件是否重复,核心是避免一次性加载整个文件到内存,尤其适合大文件场景。关键不在于“先比什么”,而在于分层验证的逻辑顺序:先快速筛,再精准判。
第一步:用物理属性做轻量级预筛
读取文件大小和最后修改时间(mtime),这两项可通过 File.length() 和 File.lastModified() 瞬间获取。如果两个文件大小不同,直接判定不重复;大小相同且修改时间也一致,才进入下一步。这一步能过滤掉绝大多数非重复文件,耗时几乎为零。
第二步:按块读取并计算哈希值
不把整个文件读进内存,而是用固定缓冲区(如 8KB 或 64KB)分块读取输入流,边读边更新哈希对象:
- 推荐使用
MessageDigest(如 SHA-256),比 MD5 更抗碰撞,安全性更高 - 缓冲区大小需权衡:太小会增加 I/O 次数;太大可能挤占堆内存,8192 字节是通用稳妥值
- 务必调用
md.update(byte[], offset, len)而非md.digest(byte[]),后者会重置状态
第三步:比对指纹而非原始内容
完成哈希计算后,得到的是字节数组,应转为十六进制字符串(如 DigestUtils.sha256Hex(is))或保持为 byte[] 进行 Arrays.equals() 比较。切忌直接比对原始输入流或文件路径——路径不同、内容相同就是典型重复文件。
第四步:注意边界与一致性
实际应用中容易出错的细节:
- 确保两个文件都以相同的编码/模式打开(如都用
FileInputStream,不混用BufferedInputStream包裹导致额外字节) - 跳过 BOM(字节序标记)仅适用于文本文件判重,二进制文件必须原样比对全部字节
- 若用于上传判重,服务端应统一使用同一哈希算法和缓冲策略,否则同一文件在不同节点算出的指纹可能不一致











