I have a folder with files which are named after timestamps.
When I try to go through each file it sorts them alphabetically and gives me this order:
/home/user/buffereddata/1
/home/user/buffereddata/100
/home/user/buffereddata/1000
/home/user/buffereddata/200
/home/user/buffereddata/2000
/home/user/buffereddata/300
But I want them sorted like this:
/home/user/buffereddata/1
/home/user/buffereddata/100
/home/user/buffereddata/200
/home/user/buffereddata/300
/home/user/buffereddata/1000
/home/user/buffereddata/2000
This is my code:
File file = new File(System.getProperty("user.home") + "/buffereddata");
if(file.exists()) {
File[] fileArray = file.listFiles();
Arrays.sort(fileArray);
for(File f : fileArray) {
System.out.println(f);
}
}
Is there some (preferably simple) way to loop through the files in the way that I want to loop through them?
Using the toCharArray() method Get the required string. Convert the given string to a character array using the toCharArray() method. Sort the obtained array using the sort() method of the Arrays class. Convert the sorted array to String by passing it to the constructor of the String array.
In Java, the collections framework provides a static method sort() that can be used to sort elements in a collection. The sort() method of the collections framework uses the merge sort algorithm to sort elements of a collection. The merge sort algorithm is based on divide and conquers rule.
Arrays.sort(fileArray, new Comparator<File>() {
public int compare(File f1, File f2) {
try {
int i1 = Integer.parseInt(f1.getName());
int i2 = Integer.parseInt(f2.getName());
return i1 - i2;
} catch(NumberFormatException e) {
throw new AssertionError(e);
}
}
});
While the other answers are correct in your specific case (where all file names in a given directory are numeric only), here's a solution that can compare mixed numeric / non-numeric file names, e.g. version-1.10.3.txt
in an intuitive way, similar to the way Windows Explorer does it:
The idea (which I have blogged about here. The idea was inspired by this answer here.) is to split a file name into numeric / non-numeric segments and then compare each individual segment from the two file names either numerically (if both are numeric), or alpha-numerically otherwise:
public final class FilenameComparator implements Comparator<String> {
private static final Pattern NUMBERS =
Pattern.compile("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
@Override public final int compare(String o1, String o2) {
// Optional "NULLS LAST" semantics:
if (o1 == null || o2 == null)
return o1 == null ? o2 == null ? 0 : -1 : 1;
// Splitting both input strings by the above patterns
String[] split1 = NUMBERS.split(o1);
String[] split2 = NUMBERS.split(o2);
for (int i = 0; i < Math.min(split1.length, split2.length); i++) {
char c1 = split1[i].charAt(0);
char c2 = split2[i].charAt(0);
int cmp = 0;
// If both segments start with a digit, sort them numerically using
// BigInteger to stay safe
if (c1 >= '0' && c1 <= '9' && c2 >= 0 && c2 <= '9')
cmp = new BigInteger(split1[i]).compareTo(new BigInteger(split2[i]));
// If we haven't sorted numerically before, or if numeric sorting yielded
// equality (e.g 007 and 7) then sort lexicographically
if (cmp == 0)
cmp = split1[i].compareTo(split2[i]);
// Abort once some prefix has unequal ordering
if (cmp != 0)
return cmp;
}
// If we reach this, then both strings have equally ordered prefixes, but
// maybe one string is longer than the other (i.e. has more segments)
return split1.length - split2.length;
}
}
You can then use the comparator as such:
Arrays.sort(fileArray, Comparators.comparing(File::getName, new FilenameComparator()));
you need a custom comparator
Arrays.sort(fileArray, new Comparator<File>() {
public int compare(File f1, File f2) {
int n1 = Integer.parseInt(f1.getName());
int n2 = Integer.parseInt(f1.getName());
return Integer.compare(n1, n2);
}});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With