You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Java Stream删除文件夹中的重复文件?

用Stream API删除内容重复的文件

你原来的方法为什么失效?

  • 直接用File流的distinct():File类的equals()方法比较的是文件路径和名称,而非内容。所以即使内容完全相同,只要文件名不同,distinct()会把它们当成不同元素,最终所有文件都会被删除。
  • 转字节数组用distinct():Java数组的equals()是引用比较,不是内容比较。两个内容完全一致的字节数组,只要是不同对象,distinct()就会认为它们不同,自然识别不了重复。

仅用Stream实现的正确方案

核心思路是:用文件内容的哈希值(比如MD5)标识重复,按哈希值分组后,每组只保留一个文件,删除其余。哈希值相同的文件,内容重复的概率几乎为100%(可忽略碰撞情况)。

代码示例:

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Map;
import java.util.stream.Collectors;

public class DuplicateFileRemover {
    public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
        File directory = new File("D:\\Photos\\Test");
        File[] files = directory.listFiles();
        if (files == null) return;

        // 按文件内容的MD5哈希分组,每组保留第一个文件
        Map<String, File> uniqueFiles = Files.list(directory.toPath())
                .filter(Files::isRegularFile)
                .collect(Collectors.toMap(
                        path -> getFileHash(path),  // 哈希值作为分组key
                        path -> path.toFile(),      // 文件对象作为value
                        (existing, replacement) -> existing  // 重复时保留第一个文件
                ));

        // 删除不在唯一文件集合里的重复文件
        Files.list(directory.toPath())
                .filter(Files::isRegularFile)
                .map(path -> path.toFile())
                .filter(file -> !uniqueFiles.containsValue(file))
                .forEach(file -> {
                    try {
                        Files.delete(file.toPath());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                });
    }

    // 计算文件MD5哈希值,转为Base64字符串方便存储
    private static String getFileHash(java.nio.file.Path path) throws IOException, NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] fileBytes = Files.readAllBytes(path);
        md.update(fileBytes);
        byte[] hashBytes = md.digest();
        return Base64.getEncoder().encodeToString(hashBytes);
    }
}

补充说明

  • 如果处理大文件,readAllBytes()可能占用过多内存,可改用流式读取计算哈希:
private static String getLargeFileHash(java.nio.file.Path path) throws IOException, NoSuchAlgorithmException {
    MessageDigest md = MessageDigest.getInstance("MD5");
    try (var inputStream = Files.newInputStream(path)) {
        byte[] buffer = new byte[8192];
        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            md.update(buffer, 0, bytesRead);
        }
    }
    byte[] hashBytes = md.digest();
    return Base64.getEncoder().encodeToString(hashBytes);
}
  • 若想保留最新/最旧文件,可修改Collectors.toMap()的第三个参数,比如(existing, replacement) -> replacement会保留最后遍历到的文件,配合Sorted()还能控制遍历顺序。

内容的提问来源于stack exchange,提问作者VegetaSan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 04:18:29