Получить файлы в каталоге, отсортированном по последнему изменению?

Есть ли в Java 7 с новыми API ввода-вывода простой способ составить список содержимого каталога по дате последнего изменения? В основном мне нужно только получить файл, который не изменялся дольше всего (отсортировать по последнему измененному возрастанию, взять первое имя файла).


person stefan.at.wpf    schedule 03.09.2012    source источник
comment
Почему он отмечен как дубликат? Этот вопрос касается Java NIO. Другой вопрос не имеет ничего общего с Java NIO. Не дубликат.   -  person Peter    schedule 15.08.2020


Ответы (6)


Нет реального "простого способа" сделать это, но это возможно:

List<Path> files = new ArrayList<>();
try(DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
    for(Path p : stream) {
        files.add(p);
    }
}

Collections.sort(files, new Comparator<Path>() {
    public int compare(Path o1, Path o2) {
        try {
            return Files.getLastModifiedTime(o1).compareTo(Files.getLastModifiedTime(o2));
        } catch (IOException e) {
            // handle exception
        }
    }
});

Это будет отсортировать файлы, которые были изменены раньше всех, файлы были последними. DirectoryStreams не перебирают подкаталоги.

person Jeffrey    schedule 03.09.2012
comment
спасибо за полное решение. File.listFiles () может сделать ваш код короче :-) - person stefan.at.wpf; 04.09.2012
comment
@ stefan.at.wpf Но тогда он не будет использовать NIO2 в соответствии с вашим запросом - person Jeffrey; 04.09.2012
comment
ах ладно, извини, не заметил этого. Мне не нужен NIO, мне просто интересно, предложит ли NIO простое решение ;-) - person stefan.at.wpf; 04.09.2012
comment
Имейте в виду, что точности lastModifiedTime может быть недостаточно для сравнения файлов. Например, при копировании группы файлов все файлы назначения будут иметь один и тот же lastModifiedTime, поэтому их нельзя будет отсортировать по нему. Это происходит потому, что точность lastModifiedTime часто устанавливается только с точностью до секунды, но не до миллисекунды. - person asmaier; 26.11.2013
comment
Комментарий @asmaier о точности lastModifiedTime важен. Для упорядоченных уникальных Коллекций, таких как TreeSet, эта ошибка может привести к .add() сбою. - person daveloyall; 03.04.2015

Слегка «поточный» вариант ответа Джеффри, который некоторым тоже может показаться проще. Проводка для полноты.

try (DirectoryStream<Path> files = Files.newDirectoryStream(path)) {
    StreamSupport.stream(files.spliterator(), false)
        .sorted((o1, o2) -> {
            try {
                return Files.getLastModifiedTime(o1).compareTo(Files.getLastModifiedTime(o2));
            } catch (IOException ex) {
                ...
            }
        })
        .filter(file -> Files.isRegularFile(file))
        .forEach(file -> {
        });
}
person ok2c    schedule 02.06.2015
comment
Почему sorted раньше filter? - person Mark Jeronimus; 28.11.2020

Используйте listFiles () для объекта каталога File. Преобразуйте массив в arrayylist. Затем отсортируйте их, используя метод статической сортировки в классе Collections с настраиваемым Comparator, который использует метод getTotalSpace () в классе Files. РЕДАКТИРОВАТЬ: используйте lastModified вместо getTotalSpace.

person Ròmário    schedule 03.09.2012

lastModified()

Возвращает время последнего изменения файла, обозначенного этим абстрактным путем.

Java 7 - API ввода-вывода

person atomman    schedule 03.09.2012
comment
Спасибо, но из каталога с примерно 100 файлами мне нужно получить самый старый, просто интересно, есть ли лучший способ, чем сравнение всех значений lastModified вручную, например передавая только параметр сортировки, а затем выбираем первую или последнюю запись в списке, в зависимости от направления сортировки. - person stefan.at.wpf; 04.09.2012
comment
Чтобы узнать, какой файл самый новый / самый старый, необходимо перебрать все файлы в цикле. Что и делает (насколько мне известно) FileFilter. Единственное, за исключением случаев, упомянутых в сообщении jdevelop (РЕДАКТИРОВАТЬ: вероятно, есть много способов добиться этого), - это создать компаратор как этот File f = new File(""); Arrays.sort(f.listFiles(), new Comparator<File>() { public int compare(File o1, File o2) { return (int)(o1.lastModified() - o2.lastModified()); } }); return f[0]; - person atomman; 04.09.2012

вы можете использовать http://docs.oracle.com/javase/1.5.0/docs/api/java/io/File.html#listFiles(java.io.FileFilter) и укажите http://docs.oracle.com/javase/1.5.0/docs/api/java/io/FileFilter.html

затем сравните http://docs.oracle.com/javase/1.5.0/docs/api/java/io/File.html#lastModified (), и все готово.

если вы заботитесь о производительности - просто возьмите один с максимальным / минимальным значением из списка файлов, что даст вам сложность O (n)

person jdevelop    schedule 03.09.2012

Примечание. Для этого решения требуется Guava.

Java IO / NIO API обеспечивает низкоуровневый доступ к спискам каталогов, но никакой обработки не выполняется, и ее оставляют на усмотрение вызывающей стороны. Новый J ava7 NIO DirectoryStream занимает минимальное место при доступе к списку каталогов для дальнейшей обработки, например сортировка.

Вот мое решение: прочтите файлы из DirectoryStream и создайте отсортированную очередь с (необязательно) ограниченным размером из потока. Вернуть самые старые / самые новые элементы из очереди.

private void listFilesOldestFirst(final File directory, final Integer maxNumberOfFiles) {

    final Builder<File> builder =
            MinMaxPriorityQueue
            .orderedBy(LastModifiedFileComparator.LASTMODIFIED_COMPARATOR);
    if( maxNumberOfFiles != null ) {
        builder.maximumSize(maxNumberOfFiles);
    }

    // queue with constant space, if maxNumberOfFiles is set, otherwise behaves like an unbound queue with an O(log n) penalty for insertion
    final MinMaxPriorityQueue<File> oldestFiles = builder.create();

    try(DirectoryStream<Path> stream = Files.newDirectoryStream(directory.toPath())) {
        for(final Path p : stream) {
            oldestFiles.add(p.toFile());
        }
    } catch (final IOException e) {
        throw new RuntimeException(e);
    }

    final File[] fileArray = oldestFiles.toArray(new File[]{});
    Arrays.sort(fileArray, oldestFiles.comparator());
    // ... use fileArray

    final ArrayList<File> arrayList = Lists.newArrayList(oldestFiles);
    Collections.sort(arrayList, oldestFiles.comparator());
    // ... use arrayList

}

Эти зависимости необходимы для MinMaxPriorityQueue и FileComparator Guava:

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>18.0</version>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.4</version>
    </dependency>

Вы также можете найти параметр filter в Files.newDirectoryStream:

    final Filter<Path> sampleFilter = new Filter<Path>() {
        @Override
        public boolean accept(final Path entry) throws IOException {
            return true; // see commons-io -> FileFilterUtils
        }
    };

    ...
    Files.newDirectoryStream(directory.toPath(), sampleFilter)
person Steve Oh    schedule 17.11.2014