无法使用 Collections(Java) 对文件名将包含时间戳的文件列表进行排序
Unable to sort list of files where the file name would contain the timestamp using Collections(Java)
我有一个包含文件列表的 arrayList,其名称确实是时间戳。
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"));
时间戳的格式是'yyyymmddHHssmm'。
我的 objective 是按照文件名中给出的时间戳的升序对这个列表进行排序。
因此,我使用 Collections.sort 方法如下:
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;
}
}
});
显然在这一行之后,您希望列表项(文件)的顺序为:
[20190512221303, 20190512222303, 20190612221053, 20190612221303, 20190612221353]
但我收到的是订单:
[20190512221303, 20190612221303, 20190512222303, 20190612221053, 20190612221353]
很明显出了点问题。
谁能指出我哪里做错了。
您可以尝试使用 java 8:
List<File> ordered = fileList.sort((o1, o2) ->
Long.valueOf(Long.valueOf(o1.getName()) - Long.valueOf(o2.getName())).intValue());
基本上您将文件名转换为数字(yyyymmddHHssmm 结构保证较新的文件将具有更大的 Long 值),然后使用比较器计算差异并使用所述比较器调用 List#sort
ordered
将保存有序的文件列表
如果您想要倒序,请像这样交换运算符:
Long.valueOf(Long.valueOf(o2.getName()) - Long.valueOf(o1.getName())).intValue()
编辑
我们注意到文件名结构是这样的:
yyyymmddHHmmss_someName.extension
因此,在执行比较之前,必须先从文件名中提取日期值。
在那种情况下,代码应该是:
fileList.sort(
(o1, o2) ->
Long.valueOf(
Long.valueOf(o1.getName().split(Pattern.quote("_"))[0])
- Long.valueOf(o2.getName().split(Pattern.quote("_"))[0]))
.intValue());
在此版本中,文件名在 _ 字符上拆分,日期参考被提取。然后将日期转换成数字,用于比较文件。
编辑2
如果文件名是动态的,并且名称中包含 yyyymmddHHmmss 引用,那么您可以这样做:
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();
});
日期引用是从文件名的任何部分提取的。
您可以在 .find()
调用中添加额外的验证,以检查文件名是否符合预期的模式。
编辑3
可以通过使用可选添加文件名模式验证来改进解决方案:
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();
});
在此解决方案中,如果任何文件名与预期模式不匹配,将使用默认值 minVal(非常旧的文件日期参考)。
希望对您有所帮助
代码中有两个主要错误
- 比较逻辑
使用
Long.compare(timeStamp1.getTime(), timeStamp2.getTime());
正确比较两个 long
数字
- 日期格式
切换 mm
--> MM
月份。
我有一个包含文件列表的 arrayList,其名称确实是时间戳。
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"));
时间戳的格式是'yyyymmddHHssmm'。
我的 objective 是按照文件名中给出的时间戳的升序对这个列表进行排序。
因此,我使用 Collections.sort 方法如下:
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;
}
}
});
显然在这一行之后,您希望列表项(文件)的顺序为:
[20190512221303, 20190512222303, 20190612221053, 20190612221303, 20190612221353]
但我收到的是订单:
[20190512221303, 20190612221303, 20190512222303, 20190612221053, 20190612221353]
很明显出了点问题。 谁能指出我哪里做错了。
您可以尝试使用 java 8:
List<File> ordered = fileList.sort((o1, o2) ->
Long.valueOf(Long.valueOf(o1.getName()) - Long.valueOf(o2.getName())).intValue());
基本上您将文件名转换为数字(yyyymmddHHssmm 结构保证较新的文件将具有更大的 Long 值),然后使用比较器计算差异并使用所述比较器调用 List#sort
ordered
将保存有序的文件列表
如果您想要倒序,请像这样交换运算符:
Long.valueOf(Long.valueOf(o2.getName()) - Long.valueOf(o1.getName())).intValue()
编辑
我们注意到文件名结构是这样的: yyyymmddHHmmss_someName.extension
因此,在执行比较之前,必须先从文件名中提取日期值。
在那种情况下,代码应该是:
fileList.sort(
(o1, o2) ->
Long.valueOf(
Long.valueOf(o1.getName().split(Pattern.quote("_"))[0])
- Long.valueOf(o2.getName().split(Pattern.quote("_"))[0]))
.intValue());
在此版本中,文件名在 _ 字符上拆分,日期参考被提取。然后将日期转换成数字,用于比较文件。
编辑2
如果文件名是动态的,并且名称中包含 yyyymmddHHmmss 引用,那么您可以这样做:
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();
});
日期引用是从文件名的任何部分提取的。
您可以在 .find()
调用中添加额外的验证,以检查文件名是否符合预期的模式。
编辑3
可以通过使用可选添加文件名模式验证来改进解决方案:
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();
});
在此解决方案中,如果任何文件名与预期模式不匹配,将使用默认值 minVal(非常旧的文件日期参考)。
希望对您有所帮助
代码中有两个主要错误
- 比较逻辑
使用
Long.compare(timeStamp1.getTime(), timeStamp2.getTime());
正确比较两个 long
数字
- 日期格式
切换 mm
--> MM
月份。