0

We have a situation where our directory has files with a prefix (say MyFile), followed by a number (e.g. MyFile1, MyFile2, MyFile3, …). We would like to return the list of filenames in the directory, but in numeric order. For example MyFile1, MyFile2, MyFile3, … , MyFile9, MyFile10, MyFile11, MyFile12 etc.).

The Java File class list() method returns the list of filenames but in lexicographic order (MyFile1, MyFile10, MyFile11, MyFile12, MyFile2, MyFile3…. , MyFile9 etc.). Is there an API call that would return the filenames in the order we want?


Addendum
A slight variant of the solution suggested in Java File.list() consistent order? has worked for me. I have created a new method called generateConsistentOrder. The code is as follows:

protected void generateConsistentOrder(String[] files, String prefixToDrop) {
        Arrays.sort(
                files,
                new Comparator<String>() {
                    public int compare(String a, String b) {
                        Integer retVal = null;
                        try {
                            Integer intA = Integer.parseInt(a.substring(a.indexOf(prefixToDrop)+prefixToDrop.length()));
                            Integer intB = Integer.parseInt(b.substring(b.indexOf(prefixToDrop)+prefixToDrop.length()));
                            retVal = intA.compareTo(intB);
                        }
                        catch (Exception e) {
                            retVal = a.compareTo(b);
                        }

                        return retVal;
                    }
                });
    }
Sandeep
  • 1,245
  • 1
  • 13
  • 33

1 Answers1

2

What you can do is to use the Files#list method that comes from the java.nio package. With that on hand, you are going to end up with a stream of Path objects, on to which could apply a Comparator that will sort them using Path#getFileName.

With than in place you need to have an implemntation of the Comparator interface in place that will scrape the number from the given file path and compare the value against some other. A simple example is this:


public class PathComparator implements Comparator<Path> {

    private static final Pattern PATTERN = Pattern.compile("\\d+");

    @Override
    public int compare(Path o1, Path o2) {
        var path1Matcher = PATTERN.matcher(o1.getFileName().toString());
        var path2Matcher = PATTERN.matcher(o2.getFileName().toString());
        Integer file1 = 0;
        Integer file2 = 0;
        if (path1Matcher.find()) {
            file1 = Integer.valueOf(path1Matcher.group());
        }

        if (path2Matcher.find()) {
            file2 = Integer.valueOf(path2Matcher.group());
        }
        return file1.compareTo(file2);
    }

}

Bringing it all together would then look like this:

public static List<Path> listOrdered(String path) {
    try (var fileStream = Files.list(Paths.get(path))) {
        return fileStream
            .sorted(new PathComparator())
            .toList();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return Collections.emptyList();
}

Note I am using Java 16 for this example, but you can easily modify it to work with older Java version.

akortex
  • 5,067
  • 2
  • 25
  • 57
  • `Path.compareTo()` is platform-dependent, and it most probably sorts strings lexicographically. You need to write a custom comparator or use some utility function. – Alex Shesterov May 31 '21 at 16:51
  • @AlexShesterov you are absolutely right and it seems I misread the question. – akortex May 31 '21 at 17:03