在Java中列出文件的最佳方法,按修改日期排序?

cwi*_*ick 234 java sorting file

我想获取目录中的文件列表,但我想对其进行排序,使得最旧的文件是第一个.我的解决方案是调用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());
    } });
Run Code Online (Sandbox Code Playgroud)

Dan*_*yer 96

我认为你的解决方案是唯一明智的方法.获取文件列表的唯一方法是使用File.listFiles(),文档声明这不保证返回的文件的顺序.因此,您需要编写一个使用File.lastModified()Comparator,并将与文件数组一起传递给Arrays.sort().


Jas*_*rff 47

如果您有许多文件,这可能会更快.这使用了decorate-sort-undecorate模式,这样每个文件的最后修改日期只被提取一次,而不是每次排序算法比较两个文件.这可能会减少从O(n log n)到O(n)的I/O调用次数.

但是,这是更多的代码,所以只有在你主要关注速度时它才会被使用,并且在实践中它的速度要快得多(我还没有检查过).

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;
Run Code Online (Sandbox Code Playgroud)

  • 最佳答案,因为如果lastModified在排序时发生变化,它可能是唯一一个阻止"比较方法违规错误"的人? (5认同)
  • 当您担心由于比较方法违规而不会获得 IllegalArgumentException 时,也应该使用它。如果有多个文件具有相同的 lastModified 值,则使用 Map 的方法将失败,这将导致忽略这些文件。这绝对应该是一个可以接受的答案。 (2认同)

小智 36

什么是类似的方法,但没有拳击到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());
    }
});
Run Code Online (Sandbox Code Playgroud)

  • 使用return Long.valueOf(f1.lastModified()).compareTo(f2.lastModified()); 相反,对于较低的api. (4认同)

Vin*_*ini 35

自Java 8以来的优雅解决方案

File[] files = directory.listFiles();
Arrays.sort(files, Comparator.comparingLong(File::lastModified));
Run Code Online (Sandbox Code Playgroud)

或者,如果您想按降序排列,只需将其反转:

File[] files = directory.listFiles();
Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed());
Run Code Online (Sandbox Code Playgroud)

  • 这确实是最简单的解决方案。对于列表:`files.sort(Comparator.comparingLong(File::lastModified));` (2认同)

小智 25

你也可以看看apache commons IO,它有一个内置的最后修改过的比较器和许多其他很好的工具来处理文件.

  • javadoc中存在一个奇怪的错误,因为javadoc说使用"LastModifiedFileComparator.LASTMODIFIED_COMPARATOR.sort(list);" 排序列表,但LASTMODIFIED_COMPARATOR声明为"Comparator <File>",因此它不会公开任何"排序"方法. (5认同)
  • 像这样使用它:[link](http://www.avajava.com/tutorials/lessons/how-do-i-sort-an-array-of-files-according-to-their-last-modified-dates的.html) (4认同)

has*_*sen 14

在Java 8中:

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


Bal*_*yan 13

进口:

org.apache.commons.io.comparator.LastModifiedFileComparator
Run Code Online (Sandbox Code Playgroud)

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

    }
Run Code Online (Sandbox Code Playgroud)


Mat*_*son 7

如果要排序的文件可以在执行排序的同时进行修改或更新:


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());
    }
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)


这两种解决方案都创建了一个临时的地图数据结构,以便为目录中的每个文件保存一个不变的上次修改时间.我们需要这样做的原因是,如果在执行排序时更新或修改了文件,那么比较器将违反比较器接口的一般合同的传递性要求,因为在比较期间最后修改的时间可能会发生变化.

另一方面,如果你知道在排序过程中不会更新或修改文件,你可以放弃提交给这个问题的任何其他答案.