Лучший способ перечислить файлы на Java, отсортированные по дате Модифицированные?

Я хочу получить список файлов в каталоге, но я хочу сортировать его таким образом, чтобы сначала были самые старые файлы. Мое решение состояло в том, чтобы вызвать File.listFiles и просто прибегнуть к списку на основе File.lastModified, но мне было интересно, есть ли лучший способ.

Изменить: Мое текущее решение, как было предложено, заключается в использовании анонимного компаратора:

File[] files = directory.listFiles();

Arrays.sort(files, new Comparator<File>(){
    public int compare(File f1, File f2)
    {
        return Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());
    } });

Ответ 1

Я думаю, что ваше решение - единственный разумный путь. Единственный способ получить список файлов - использовать File.listFiles(), и в документации указано, что это не гарантирует гарантий порядка файлы возвращены. Поэтому вам нужно написать Comparator, который использует File.lastModified() и передайте это вместе с массивом файлов Arrays.sort().

Ответ 2

Это может быть быстрее, если у вас много файлов. Это использует шаблон decorate-sort-undecorate, так что дата последнего изменения каждого файла выбирается только один раз, а не каждый раз, когда алгоритм сортировки сравнивает два файла. Это потенциально уменьшает количество вызовов ввода-вывода от O (n log n) до O (n).

Однако это больше кода, поэтому это следует использовать, только если вы в основном относитесь к скорости, и на практике это значительно быстрее (что я еще не проверял).

class Pair implements Comparable {
    public long t;
    public File f;

    public Pair(File file) {
        f = file;
        t = file.lastModified();
    }

    public int compareTo(Object o) {
        long u = ((Pair) o).t;
        return t < u ? -1 : t == u ? 0 : 1;
    }
};

// Obtain the array of (file, timestamp) pairs.
File[] files = directory.listFiles();
Pair[] pairs = new Pair[files.length];
for (int i = 0; i < files.length; i++)
    pairs[i] = new Pair(files[i]);

// Sort them by timestamp.
Arrays.sort(pairs);

// Take the sorted pairs and extract only the file part, discarding the timestamp.
for (int i = 0; i < files.length; i++)
    files[i] = pairs[i].f;

Ответ 3

Как насчет аналогичного подхода, но без бокса для объектов Long:

File[] files = directory.listFiles();

Arrays.sort(files, new Comparator<File>() {
    public int compare(File f1, File f2) {
        return Long.compare(f1.lastModified(), f2.lastModified());
    }
});

Ответ 4

Элегантное решение начиная с Java 8:

File[] files = directory.listFiles();
Arrays.sort(files, Comparator.comparingLong(File::lastModified));

Или, если вы хотите в порядке убывания, просто измените его:

File[] files = directory.listFiles();
Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed());

Ответ 6

В Java 8:

Arrays.sort(files, (a, b) -> Long.compare(a.lastModified(), b.lastModified()));

Ответ 7

Импорт:

org.apache.commons.io.comparator.LastModifiedFileComparator

Apache Commons

Код:

public static void main(String[] args) throws IOException {
        File directory = new File(".");
        // get just files, not directories
        File[] files = directory.listFiles((FileFilter) FileFileFilter.FILE);

        System.out.println("Default order");
        displayFiles(files);

        Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_COMPARATOR);
        System.out.println("\nLast Modified Ascending Order (LASTMODIFIED_COMPARATOR)");
        displayFiles(files);

        Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_REVERSE);
        System.out.println("\nLast Modified Descending Order (LASTMODIFIED_REVERSE)");
        displayFiles(files);

    }

Ответ 8

Если сортируемые файлы могут быть изменены или обновлены одновременно, сортировка выполняется:


Ява 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;
}


Оба этих решения создают временную структуру данных карты, чтобы сохранить постоянное время последнего изменения для каждого файла в каталоге. Причина, по которой мы должны это сделать, заключается в том, что если ваши файлы обновляются или модифицируются во время выполнения сортировки, тогда ваш компаратор будет нарушать требование транзитивности общего контракта интерфейса компаратора, поскольку время последнего изменения может изменяться во время сравнения.

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

Ответ 9

public String[] getDirectoryList(String path) {
    String[] dirListing = null;
    File dir = new File(path);
    dirListing = dir.list();

    Arrays.sort(dirListing, 0, dirListing.length);
    return dirListing;
}

Ответ 10

Вы можете попробовать guava Ordering:

Function<File, Long> getLastModified = new Function<File, Long>() {
    public Long apply(File file) {
        return file.lastModified();
    }
};

List<File> orderedFiles = Ordering.natural().onResultOf(getLastModified).
                          sortedCopy(files);

Ответ 11

Вы можете использовать Apache LastModifiedFileComparator библиотека

 import org.apache.commons.io.comparator.LastModifiedFileComparator;  


File[] files = directory.listFiles();
        Arrays.sort(files, LastModifiedFileComparator.LASTMODIFIED_COMPARATOR);
        for (File file : files) {
            Date lastMod = new Date(file.lastModified());
            System.out.println("File: " + file.getName() + ", Date: " + lastMod + "");
        }

Ответ 12

private static List<File> sortByLastModified(String dirPath) {
    List<File> files = listFilesRec(dirPath);
    Collections.sort(files, new Comparator<File>() {
        public int compare(File o1, File o2) {
            return Long.compare(o1.lastModified(), o2.lastModified());
        }
    });
    return files;
}

Ответ 13

Collections.sort(listFiles, new Comparator<File>() {
        public int compare(File f1, File f2) {
            return Long.compare(f1.lastModified(), f2.lastModified());
        }
    });

где listFiles - это коллекция всех файлов в ArrayList

Ответ 14

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

Ниже код может быть полезен кому-то -

File downloadDir = new File("mypath");    
File[] list = downloadDir.listFiles();
    for (int i = list.length-1; i >=0 ; i--) {
        //use list.getName to get the name of the file
    }

Спасибо

Ответ 15

Существует также совершенно другой способ, который может быть даже проще, поскольку мы не имеем дело с большими числами.

Вместо сортировки всего массива после того, как вы извлекли все имена файлов и даты lastModified, вы можете просто вставить каждое отдельное имя файла сразу после того, как вы извлекли его в правильной позиции списка.

Вы можете сделать это так:

list.add(1, object1)
list.add(2, object3)
list.add(2, object2)

После того, как вы добавите объект 2 в положение 2, он переместит объект 3 в положение 3.

Ответ 16

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

Используйте строку фиксированной длины 20, поместите в нее измененную дату (длинную) и заполните начальными нулями. Затем просто добавьте имя файла к этой строке:

String modified_20_digits = ("00000000000000000000".concat(Long.toString(temp.lastModified()))).substring(Long.toString(temp.lastModified()).length()); 

result_filenames.add(modified_20_digits+temp.getAbsoluteFile().toString());

Что здесь происходит, это:

Имя файла1: C:\data\file1.html Последнее изменение: 1532914451455 Последнее изменение 20 цифр: 00000001532914451455

Имя файла1: C:\data\file2.html Последнее изменение: 1532918086822 Последнее изменение 20 цифр: 00000001532918086822

преобразует имена файлов в:

Имя файла1: 00000001532914451455C:\data\file1.html

Имя файла2: 00000001532918086822C:\data\file2.html

Затем вы можете просто отсортировать этот список.

Все, что вам нужно сделать, это снова обрезать 20 символов позже (в Java 8 вы можете вырезать его для всего массива всего одной строкой, используя функцию .replaceAll)