首页 > 解决方案 > 如何删除目录中的所有重复文件?爪哇

问题描述

我如何编写代码才能准确删除我之前使用此代码获得的重复项。??请具体回答,因为我是java新手。我对java有非常基本的了解。

private static MessageDigest messageDigest;
    static {
        try {
            messageDigest = MessageDigest.getInstance("SHA-512");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("cannot initialize SHA-512 hash function", e);
        }
    }
public static void findDuplicatedFiles(Map<String, List<String>> lists, File directory) {
        for (File child : directory.listFiles()) {
            if (child.isDirectory()) {
                findDuplicatedFiles(lists, child);
            } else {
                try {
                    FileInputStream fileInput = new FileInputStream(child);
                    byte fileData[] = new byte[(int) child.length()];
                    fileInput.read(data);
                    fileInput.close();
                    String uniqueFileHash = new BigInteger(1, md.digest(fileData)).toString(16);
                    List<String> list = lists.get(uniqueFileHash);
                    if (list == null) {
                        list = new LinkedList<String>();
                        lists.put(uniqueFileHash, list);
                    }
                    list.add(child.getAbsolutePath());
                } catch (IOException e) {
                    throw new RuntimeException("cannot read file " + child.getAbsolutePath(), e);
                }
            }
        }
    }
Map<String, List<String>> lists = new HashMap<String, List<String>>();
        FindDuplicates.findDuplicateFiles(lists, dir);
        for (List<String> list : lists.values()) {
            if (list.size() > 1) {
                System.out.println("\n");
                for (String file : list) {
                    System.out.println(file);
                }
            }
        }
        System.out.println("\n");
      

标签: java

解决方案


Path使用 NIO / class扫描目录更容易,Files因为它避免了类的尴尬递归File,并且对于更深的目录树来说更快。

这是一个示例扫描器,它返回一个Stream重复项 - 即流中的每个项目都是一个List<Path>- 一组两个或更多相同的文件。

// Scan a directory and returns Stream of List<Path> where each list has 2 or more duplicates
static Stream<List<Path>> findDuplicates(Path dir) throws IOException {
    Map<Long, List<Path>> candidates = new HashMap<>();
    BiPredicate<Path, BasicFileAttributes> biPredicate = (p,a)->a.isRegularFile()
               && candidates.computeIfAbsent(Long.valueOf(a.size())
                                           , k -> new ArrayList<>()).add(p);
    try(var stream = Files.find(dir, Integer.MAX_VALUE, biPredicate)) {
       stream.count();
    }
    Predicate<? super List<Path>> twoOrMore = paths -> paths.size() > 1;
    return candidates.values().stream()
                          .filter(twoOrMore)
                          .flatMap(Duplicate::duplicateChecker)
                          .filter(twoOrMore);
}

上面的代码首先整理具有相同文件大小的候选者,然后使用一个flatMap操作来比较所有这些候选者以获得完全匹配的文件,其中每个文件都相同List<Path>

// Checks possible list of duplicates, and returns stream of definite duplicates
private static Stream<List<Path>> duplicateChecker(List<Path> sameLenPaths) {
    List<List<Path>> groups = new ArrayList<>();
    try {
        for (Path p : sameLenPaths) {
            List<Path> match = null;
            for (List<Path> g : groups) {
                Path prev = g.get(0);
                if(Files.mismatch(prev, p) < 0) {
                    match = g;
                    break;
                }
            }
            if (match == null)
                groups.add(match = new ArrayList<>());
            match.add(p);
        }
    } catch(IOException io) {
        throw new UncheckedIOException(io);
    }
    return groups.stream();
}

最后是一个示例启动器:

public static void main(String[] args) throws IOException {
    Path dir = Path.of(args[0]);

    Stream<List<Path>> duplicates = findDuplicates(dir);
    long count = duplicates.peek(System.out::println).count();
    System.out.println("Found "+count+" groups of duplicate files in: "+dir);
}

您将需要使用Files.delete- 我没有Files.delete在末尾添加来处理重复文件列表,以便您可以在决定删除它们之前检查结果。

// findDuplicates(dir).flatMap(List::stream).forEach(dup -> {
//     try {
//         Files.delete(dup);
//     } catch(IOException io) {
//         throw new UncheckedIOException(io);
//     }
// });

推荐阅读