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

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 based on File.lastModified, but I was wondering if there was a better way.

Edit: My current solution, as suggested, is to use an anonymous Comparator:

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

This question is related to java file sorting

The answer is


You can use Apache LastModifiedFileComparator library

 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 + "");
        }

There is also a completely different way which may be even easier, as we do not deal with large numbers.

Instead of sorting the whole array after you retrieved all filenames and lastModified dates, you can just insert every single filename just after you retrieved it at the right position of the list.

You can do it like this:

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

After you add object2 to position 2, it will move object3 to position 3.


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!


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;

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

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

There is a very easy and convenient way to handle the problem without any extra comparator. Just code the modified date into the String with the filename, sort it, and later strip it off again.

Use a String of fixed length 20, put the modified date (long) into it, and fill up with leading zeros. Then just append the filename to this string:

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

What happens is this here:

Filename1: C:\data\file1.html Last Modified:1532914451455 Last Modified 20 Digits:00000001532914451455

Filename1: C:\data\file2.html Last Modified:1532918086822 Last Modified 20 Digits:00000001532918086822

transforms filnames to:

Filename1: 00000001532914451455C:\data\file1.html

Filename2: 00000001532918086822C:\data\file2.html

You can then just sort this list.

All you need to do is to strip the 20 characters again later (in Java 8, you can strip it for the whole Array with just one line using the .replaceAll function)


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

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

You can try 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);

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

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;

Imports :

org.apache.commons.io.comparator.LastModifiedFileComparator

Apache Commons

Code :

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

    }

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


You can use Apache LastModifiedFileComparator library

 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 + "");
        }

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


What's about similar approach, but without boxing to the Long objects:

File[] files = directory.listFiles();

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

Imports :

org.apache.commons.io.comparator.LastModifiedFileComparator

Apache Commons

Code :

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

    }

There is a very easy and convenient way to handle the problem without any extra comparator. Just code the modified date into the String with the filename, sort it, and later strip it off again.

Use a String of fixed length 20, put the modified date (long) into it, and fill up with leading zeros. Then just append the filename to this string:

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

What happens is this here:

Filename1: C:\data\file1.html Last Modified:1532914451455 Last Modified 20 Digits:00000001532914451455

Filename1: C:\data\file2.html Last Modified:1532918086822 Last Modified 20 Digits:00000001532918086822

transforms filnames to:

Filename1: 00000001532914451455C:\data\file1.html

Filename2: 00000001532918086822C:\data\file2.html

You can then just sort this list.

All you need to do is to strip the 20 characters again later (in Java 8, you can strip it for the whole Array with just one line using the .replaceAll function)


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

where listFiles is the collection of all files in ArrayList


In Java 8:

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


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

You might also look at apache commons IO, it has a built in last modified comparator and many other nice utilities for working with files.


You can try 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);

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

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!


You might also look at apache commons IO, it has a built in last modified comparator and many other nice utilities for working with 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;
}

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

where listFiles is the collection of all files in ArrayList


What's about similar approach, but without boxing to the Long objects:

File[] files = directory.listFiles();

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

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

There is also a completely different way which may be even easier, as we do not deal with large numbers.

Instead of sorting the whole array after you retrieved all filenames and lastModified dates, you can just insert every single filename just after you retrieved it at the right position of the list.

You can do it like this:

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

After you add object2 to position 2, it will move object3 to position 3.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to file

Gradle - Move a folder from ABC to XYZ Difference between opening a file in binary vs text Angular: How to download a file from HttpClient? Python error message io.UnsupportedOperation: not readable java.io.FileNotFoundException: class path resource cannot be opened because it does not exist Writing JSON object to a JSON file with fs.writeFileSync How to read/write files in .Net Core? How to write to a CSV line by line? Writing a dictionary to a text file? What are the pros and cons of parquet format compared to other formats?

Examples related to sorting

Sort Array of object by object field in Angular 6 Sorting a list with stream.sorted() in Java How to sort dates from Oldest to Newest in Excel? how to sort pandas dataframe from one column Reverse a comparator in Java 8 Find the unique values in a column and then sort them pandas groupby sort within groups pandas groupby sort descending order Efficiently sorting a numpy array in descending order? Swift: Sort array of objects alphabetically