
Java 里怎么算文件的 MD5 值?别用 MessageDigest 直接读整个文件到内存
大文件(比如几百 MB)用 FileInputStream.readAllBytes() 或直接 Files.readAllBytes() 丢给 MessageDigest.update(),会 OOM。真实场景下必须流式计算。
- 用
FileInputStream+MessageDigest分块更新,每次最多 8192 字节 - 别忘了调用
digest()拿最终结果,不是digest(byte[])的重载版本——那个是把输入先拷贝再 digest,照样吃内存 - 十六进制转换别手写循环,用
String.format("%02x", b)或Hex.encodeHexString()(如果用了 Apache Commons Codec)
判断两个文件是否相同,只比 MD5 安全吗?
MD5 碰撞虽在理论层面存在,但对普通同步工具够用;真正要防的是“文件没变但时间戳变了”或“空文件 vs 零字节文件”这种低级误判。
- 先快速比大小:
Files.size(path1) != Files.size(path2)→ 直接不等,跳过 MD5 - 大小相同时,再比 MD5;大小为 0 时可直接认定相等,不用 digest
- 不要只依赖最后修改时间(
Files.getLastModifiedTime()),它易被外部操作篡改,且 FAT32 精度只有 2 秒
Java 复制文件用 Files.copy() 还是 Files.move()?注意目标路径已存在时的行为
Files.copy() 默认遇到目标存在就抛 FileAlreadyExistsException;Files.move() 同理。同步工具里几乎总得覆盖,但不能粗暴加 REPLACE_EXISTING 就完事。
- 复制前先检查目标是否存在,存在则用
StandardCopyOption.REPLACE_EXISTING - 如果源和目标在同一文件系统,
Files.move()更快(底层可能是 rename),但仅当你要“移动+重命名”时才用;同步是“拷贝+覆盖”,坚持用copy() - Windows 下目标正在被其他程序打开时,
copy()仍可能失败,捕获AccessDeniedException并提示用户手动关掉占用进程
同步逻辑里怎么避免重复扫描或漏同步?遍历目录时容易踩哪些坑
递归遍历用 Files.walk() 看似方便,但它默认不处理符号链接,也不控制深度,更不会自动跳过临时文件。
立即学习“Java免费学习笔记(深入)”;
- 用
Files.walk(path, 10)限制最大深度,防止无限嵌套死循环 - 加
FileVisitOption.FOLLOW_LINKS要谨慎——万一有循环软链,walk()会卡住或爆栈;建议默认不跟随,真需要时单独处理 - 过滤掉常见临时文件:
path.getFileName().toString().startsWith(".") || path.toString().endsWith("~") || path.toString().endsWith(".tmp") - 别用
listFiles(),它不支持 NIO 的异常传播,遇到权限错误直接返回 null,很难 debug









