Сортировка Изменение файлов с измененным временем без ошибки сравнения

У меня есть код, который удаляет все файлы в каталоге, за исключением последних 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.

Ответ 1

Мой вопрос: как бы вы решили эту проблему и удалили нужные файлы?

Я предлагаю вам взять временные метки всех файлов и кешировать их. Сортировка, используя эти тайники. Таким образом, они будут отсортированы с использованием согласованного времени.

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 */);

Ответ 2

Взято из моего ответа на более общий вопрос. Лучший способ перечислить файлы в 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 List<File> files = 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 files;
}