Reputation: 1040
I have an arrayList that contains list of files, whose names are indeed timestamps.
List<File> fileList = new ArrayList<>();
fileList.add(new File("20190612221053"));
fileList.add(new File("20190512221303"));
fileList.add(new File("20190612221353"));
fileList.add(new File("20190512222303"));
fileList.add(new File("20190612221303"));
The format of the time stamp is 'yyyymmddHHssmm'.
My objective is to sort this list in ascending order of the timestamps given in the file names.
Accordingly, I am using Collections.sort method as below:
Collections.sort(fileList, new Comparator<File>() {
@Override
public int compare(File file1, File file2) {
Date timeStamp1=null,timeStamp2=null;
try {
timeStamp1 = new SimpleDateFormat("yyyymmddHHssmm").parse(file1.getName());
} catch (ParseException e) {
e.printStackTrace();
}
try {
timeStamp2 = new SimpleDateFormat("yyyymmddHHssmm").parse(file2.getName());
} catch (ParseException e) {
e.printStackTrace();
}
if(timeStamp1!=null && timeStamp2!=null && timeStamp1.getTime()!=timeStamp2.getTime() ) {
return (timeStamp1.getTime() > timeStamp2.getTime()) ? 1 : -1;
}
else {
return 0;
}
}
});
Obviously after this line, you'd expect the list items(files) to be in the order:
[20190512221303, 20190512222303, 20190612221053, 20190612221303, 20190612221353]
But instead I am getting the order:
[20190512221303, 20190612221303, 20190512222303, 20190612221053, 20190612221353]
CLearly something is going wrong. Can somebody please point out where I am doing it wrong.
Upvotes: 3
Views: 281
Reputation: 240928
There are two bugs major in the code
Use
Long.compare(timeStamp1.getTime(), timeStamp2.getTime());
to do proper Comparison of two long
numbers
switch mm
--> MM
for month.
Upvotes: 1
Reputation: 1817
You can try this using java 8:
List<File> ordered = fileList.sort((o1, o2) ->
Long.valueOf(Long.valueOf(o1.getName()) - Long.valueOf(o2.getName())).intValue());
Basically you transform the file names into numbers (the yyyymmddHHssmm structure guarantees that newer files will have greater Long values) , then calculate the difference using a comparator and calling List#sort with said comparator
ordered
will hold the ordered list of files
If you want reverse order then swap the operators like this:
Long.valueOf(Long.valueOf(o2.getName()) - Long.valueOf(o1.getName())).intValue()
it's been noted that the filename structure goes like this: yyyymmddHHmmss_someName.extension
Hence, the date value must first be extracted from the filename before perfoming the comparation.
In that case, the code should be:
fileList.sort(
(o1, o2) ->
Long.valueOf(
Long.valueOf(o1.getName().split(Pattern.quote("_"))[0])
- Long.valueOf(o2.getName().split(Pattern.quote("_"))[0]))
.intValue());
In this version the filename is splitted on the _ character the date reference is extracted. Then the date is converted into a number and is used to compare files.
If the filename is dynamic and it contains a yyyymmddHHmmss reference within the name, then you can do something like this:
Pattern pattern = Pattern.compile("\\d{14}");
fileList.sort(
(o1, o2) -> {
Matcher m1 = pattern.matcher(o1.getName());
m1.find();
String date1 = m1.group(0);
Long num1 = Long.valueOf(date1);
Matcher m2 = pattern.matcher(o2.getName());
m2.find();
String date2 = m2.group(0);
Long num2 = Long.valueOf(date2);
return Long.valueOf(num1 - num2).intValue();
});
The date reference is extracted from any part of the filename.
You can add extra validations on the .find()
calls to check if the filename respects the expected pattern.
The solution can be refined by adding filename pattern validation using Optional:
long minVal = 19700101000000L ;
Pattern pattern = Pattern.compile("\\d{14}");
fileList.sort(
(o1, o2) -> {
Long num1 =
Optional.of(pattern.matcher(o1.getName()))
.filter(Matcher::find)
.map(m -> Long.valueOf(m.group(0)))
.orElse(minVal);
Long num2 =
Optional.of(pattern.matcher(o2.getName()))
.filter(Matcher::find)
.map(m -> Long.valueOf(m.group(0)))
.orElse(minVal);
return Long.valueOf(num1 - num2).intValue();
});
In this solution if any of the filenames don't match the expected pattern, a default value of minVal (very old file date reference) is used.
Hope this helps
Upvotes: 1