按修改时间排序更改文件而不使用比较方法违规错误

时间:2013-12-06 18:27:20

标签: java file sorting

我有代码删除目录中的所有文件,除了最近修改过的 n 。代码从目录中获取File个对象的列表,使用查看File.lastModifedTime()的比较器对它们进行排序,然后删除相应的子列表。

当我们升级到Java 7时,程序开始抛出java.lang.IllegalArgumentException: Comparison method violates its general contract!。我怀疑这是因为在排序完成之前修改了文件(正常行为),因此比较器在检查每个文件的最后修改时间时返回不一致的值。

我的问题是,您如何解决此问题并删除正确的文件?

我读到的一个建议是在排序之前将文件存储在地图中,并将其上次修改时间,这样在比较完成后,将从地图中查找最后修改的时间。但是,如果文件在排序中更改,则地图不会更新,所以最终是否会删除错误的文件?

我想到的其他想法是使用Java NIO的文件监视来保存排序列表,并在文件发生变化时重新排序。但这看起来相当复杂。

我还想到了一种在try-catch语句中包装排序的强力方法,如果遇到比较方法违规,只需重试整个排序。

最后,我可以设置java.util.Arrays.useLegacyMergeSort属性,然后回到静默忽略Java 6的方式。

2 个答案:

答案 0 :(得分:0)

  

我的问题是,您如何解决此问题并删除正确的文件?

我建议您获取所有文件的时间戳并缓存它们。使用这些缓存时间排序。这样,他们将使用一致的时间进行排序。

File[] files = ...
final Map<File, Long> modified = new HashMap<File, Long>();
for(File file: files)
    modified.put(file, file.lastModified());
Arrays.sort(files, /* Comparator using 'modified' Map */);

答案 1 :(得分:0)

根据我对更普遍的问题Best way to list files in Java, sorted by Date Modified?的回答

Java 8 +

private static List<Path> listFilesOldestFirst(final String directoryPath) throws IOException {
    try (final Stream<Path> fileStream = Files.list(Paths.get(directoryPath))) {
        return fileStream
            .map(Path::toFile)
            .collect(Collectors.toMap(Function.identity(), File::lastModified))
            .entrySet()
            .stream()
            .sorted(Map.Entry.comparingByValue())
//            .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))  // replace the previous line with this line if you would prefer files listed newest first
            .map(Map.Entry::getKey)
            .map(File::toPath)  // remove this line if you would rather work with a List<File> instead of List<Path>
            .collect(Collectors.toList());
    }
}

Java 7

private static List<File> listFilesOldestFirst(final String directoryPath) throws IOException {
    final Collection<File> result = Arrays.asList(new File(directoryPath).listFiles());
    final Map<File, Long> constantLastModifiedTimes = new HashMap<File,Long>();
    for (final File f : files) {
        constantLastModifiedTimes.put(f, f.lastModified());
    }
    Collections.sort(files, new Comparator<File>() {
        @Override
        public int compare(final File f1, final File f2) {
            return constantLastModifiedTimes.get(f1).compareTo(constantLastModifiedTimes.get(f2));
        }
    });
    return result;
}