Best way to list files in Java, sorted by Date Modified?

后端 未结 17 897
-上瘾入骨i
-上瘾入骨i 2020-11-22 11:51

I want to get a list of files in a directory, but I want to sort it such that the oldest files are first. My solution was to call File.listFiles and just resort the list ba

相关标签:
17条回答
  • 2020-11-22 12:18

    If the files you are sorting can be modified or updated at the same time the sort is being performed:


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


    Both of these solutions create a temporary map data structure to save off a constant last modified time for each file in the directory. The reason we need to do this is that if your files are being updated or modified while your sort is being performed then your comparator will be violating the transitivity requirement of the comparator interface's general contract because the last modified times may be changing during the comparison.

    If, on the other hand, you know the files will not be updated or modified during your sort, you can get away with pretty much any other answer submitted to this question, of which I'm partial to:

    Java 8+ (No concurrent modifications during sort)

    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)
                .sorted(Comparator.comparing(File::lastModified))
                .map(File::toPath)  // remove this line if you would rather work with a List<File> instead of List<Path>
                .collect(Collectors.toList());
        }
    }
    

    Note: I know you can avoid the translation to and from File objects in the above example by using Files::getLastModifiedTime api in the sorted stream operation, however, then you need to deal with checked IO exceptions inside your lambda which is always a pain. I'd say if performance is critical enough that the translation is unacceptable then I'd either deal with the checked IOException in the lambda by propagating it as an UncheckedIOException or I'd forego the Files api altogether and deal only with File objects:

    final List<File> sorted = Arrays.asList(new File(directoryPathString).listFiles());
    sorted.sort(Comparator.comparing(File::lastModified));
    
    0 讨论(0)
  • 2020-11-22 12:20

    I came to this post when i was searching for the same issue but in android. I don't say this is the best way to get sorted files by last modified date, but its the easiest way I found yet.

    Below code may be helpful to someone-

    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
        }
    

    Thanks

    0 讨论(0)
  • 2020-11-22 12:20

    A slightly more modernized version of the answer of @jason-orendorf.

    Note: this implementation keeps the original array untouched, and returns a new array. This might or might not be desirable.

    files = Arrays.stream(files)
            .map(FileWithLastModified::ofFile)
            .sorted(comparingLong(FileWithLastModified::lastModified))
            .map(FileWithLastModified::file)
            .toArray(File[]::new);
    
    private static class FileWithLastModified {
        private final File file;
        private final long lastModified;
    
        private FileWithLastModified(File file, long lastModified) {
            this.file = file;
            this.lastModified = lastModified;
        }
    
        public static FileWithLastModified ofFile(File file) {
            return new FileWithLastModified(file, file.lastModified());
        }
    
        public File file() {
            return file;
        }
    
        public long lastModified() {
            return lastModified;
        }
    }
    

    But again, all credits to @jason-orendorf for the idea!

    0 讨论(0)
  • 2020-11-22 12:21

    This might be faster if you have many files. This uses the decorate-sort-undecorate pattern so that the last-modified date of each file is fetched only once rather than every time the sort algorithm compares two files. This potentially reduces the number of I/O calls from O(n log n) to O(n).

    It's more code, though, so this should only be used if you're mainly concerned with speed and it is measurably faster in practice (which I haven't checked).

    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;
    
    0 讨论(0)
  • 2020-11-22 12:21
    public String[] getDirectoryList(String path) {
        String[] dirListing = null;
        File dir = new File(path);
        dirListing = dir.list();
    
        Arrays.sort(dirListing, 0, dirListing.length);
        return dirListing;
    }
    
    0 讨论(0)
  • 2020-11-22 12:22

    Elegant solution since Java 8:

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

    Or, if you want it in descending order, just reverse it:

    File[] files = directory.listFiles();
    Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed());
    
    0 讨论(0)
提交回复
热议问题