it-roy-ru.com

Лучший способ перечислить файлы в 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());
    } });
215
cwick

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

92
Dan Dyer

Это может быть быстрее, если у вас много файлов. При этом используется шаблон 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;
44
Jason Orendorff

Что касается аналогичного подхода, но без привязки к объектам 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());
    }
});
32
PhannGor

Вы также можете посмотреть на Apache commons IO , он имеет встроенный последний измененный компаратор и многие другие утилиты Nice для работы с файлами.

23
user17163

Элегантное решение начиная с 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());
22
viniciussss

В Java 8:

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

14
hasen

Импорт:

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

    }
10
Balaji Boggaram Ramanarayan

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


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;
}


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

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

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

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

Вы можете использовать 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 + "");
        }
1
Vikas
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;
}
1
Jaydev

Вы можете попробовать гуаву Заказ :

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);
1
Vitalii Fedorenko
Collections.sort(listFiles, new Comparator<File>() {
        public int compare(File f1, File f2) {
            return Long.compare(f1.lastModified(), f2.lastModified());
        }
    });

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

0
Anand Savjani

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

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

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

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

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

0
user4378029

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

Используйте строку фиксированной длины 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)

0
user4378029

Я пришел к этому сообщению, когда искал ту же проблему, но в 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
    }

Спасибо

0
ezcodr