Получаване на файлове в директория, сортирани по последна промяна?

В Java 7 с новите I/O 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 на директорията. Преобразувайте масива в списък с масиви. След това ги сортирайте, като използвате статичния метод за сортиране в класа Collections с персонализиран Comparator, който използва метода getTotalSpace() във Files. РЕДАКТИРАНЕ: Използвайте lastModified вместо getTotalSpace.

person Ròmário    schedule 03.09.2012

lastModified()

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

Java 7 - IO 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 осигурява достъп на ниско ниво до списъци с директории, но няма извършена обработка, което е оставено на повикващия. Новият Java7 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

}

Тези зависимости са необходими за Guava MinMaxPriorityQueue и FileComparator:

    <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