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

StackOverflow https://stackoverflow.com/questions/203030

  •  03-07-2019
  •  | 
  •  

Вопрос

Я хочу получить список файлов в каталоге, но я хочу отсортировать его таким образом, чтобы первыми были самые старые файлы.Мое решение состояло в том, чтобы вызвать 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());
    } });
Это было полезно?

Решение

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

Другие советы

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

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

File[] files = directory.listFiles();

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

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

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

В Java 8:

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

Импорт :

org.apache.commons.io.comparator.LastModifiedFileComparator

Общее Достояние Apache

Код :

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

    }

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


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


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

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

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

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

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

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

Вы можете использовать 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 + "");
        }
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;
}
Collections.sort(listFiles, new Comparator<File>() {
        public int compare(File f1, File f2) {
            return Long.compare(f1.lastModified(), f2.lastModified());
        }
    });

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

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

Спасибо

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

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

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)

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

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

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

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

После того, как вы добавите object2 в позицию 2, он переместит object3 в позицию 3.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top