我想获取目录中的文件列表,但我想对其进行排序,使得最旧的文件是第一个。我的解决方案是调用File.listFiles并根据File.lastModified求助于列表,但我想知道是否有更好的方法。
编辑:我建议的当前解决方案是使用匿名比较器:
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());
} });
答案 0 :(得分:94)
我认为您的解决方案是唯一明智的方法。获取文件列表的唯一方法是使用File.listFiles(),文档说明这不能保证返回文件的顺序。因此,您需要编写一个使用Comparator的File.lastModified(),并将其与文件数组一起传递给Arrays.sort()。
答案 1 :(得分:45)
如果你有很多文件,这可能会更快。这使用了decorate-sort-undecorate模式,这样每个文件的最后修改日期只能一次而不是每次排序算法比较两个文件时。这可能会减少从O(n log n)到O(n)的I / O调用次数。
这是更多的代码,所以只有在你主要关心速度时它才会被使用,而且在实践中它的速度要快得多(我没有检查过)。
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;
答案 2 :(得分:33)
类似的方法是什么,但没有拳击到Long对象:
File[] files = directory.listFiles();
Arrays.sort(files, new Comparator<File>() {
public int compare(File f1, File f2) {
return Long.compare(f1.lastModified(), f2.lastModified());
}
});
答案 3 :(得分:28)
File[] files = directory.listFiles();
Arrays.sort(files, Comparator.comparingLong(File::lastModified));
或者,如果您想按降序排列,只需将其反转:
File[] files = directory.listFiles();
Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed());
答案 4 :(得分:25)
你也可以看一下apache commons IO,它有一个内置的last modified comparator和许多其他很好的工具来处理文件。
答案 5 :(得分:14)
在Java 8中:
Arrays.sort(files, (a, b) -> Long.compare(a.lastModified(), b.lastModified()));
答案 6 :(得分:12)
进口:
org.apache.commons.io.comparator.LastModifiedFileComparator
代码:
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);
}
答案 7 :(得分:5)
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());
}
}
private static List<File> listFilesOldestFirst(final String directoryPath) throws IOException {
final Collection<File> result = 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 result;
}
这两种解决方案都创建了一个临时的地图数据结构,以便为目录中的每个文件保存一个不变的上次修改时间。我们需要这样做的原因是,如果在执行排序时更新或修改了文件,那么比较器将违反比较器接口的一般合同的传递性要求,因为在比较期间最后修改的时间可能会发生变化。
另一方面,如果您知道在排序过程中不会更新或修改文件,您可以放弃提交此问题的其他任何答案。
答案 8 :(得分:2)
public String[] getDirectoryList(String path) {
String[] dirListing = null;
File dir = new File(path);
dirListing = dir.list();
Arrays.sort(dirListing, 0, dirListing.length);
return dirListing;
}
答案 9 :(得分:1)
您可以使用Apache LastModifiedFileComparator库
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 + "");
}
答案 10 :(得分:1)
您可以尝试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);
答案 11 :(得分:1)
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;
}
答案 12 :(得分:1)
Collections.sort(listFiles, new Comparator<File>() {
public int compare(File f1, File f2) {
return Long.compare(f1.lastModified(), f2.lastModified());
}
});
其中listFiles
是ArrayList
答案 13 :(得分:0)
当我在android
搜索同样的问题时,我来到这篇文章。
我不是说这是在上次修改日期之前获取排序文件的最佳方式,但这是我发现的最简单方法。
下面的代码可能对某人有帮助 -
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
}
由于
答案 14 :(得分:0)
@ jason-orendorf的answer的现代化版本。
注意:此实现使原始数组保持不变,并返回一个 new 数组。这可能或可能不希望。
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;
}
}
但是同样,所有{@ {3}}都归功于@ jason-orendorf!
答案 15 :(得分:0)
如果有人正在寻找它,这是 Kotlin 的做法:
val filesList = directory.listFiles()
filesList?.let{ list ->
Arrays.sort(list) {
f1, f2 -> f2.lastModified().compareTo(f1.lastModified())
}
}
答案 16 :(得分:-1)
还有另一种完全不同的方法,可能会更容易,因为我们不处理大量数字。
检索所有文件名和lastModified日期后,无需对整个数组进行排序,而只需在检索到文件名后将其插入列表的正确位置即可。
您可以这样做:
list.add(1, object1)
list.add(2, object3)
list.add(2, object2)
在将对象2添加到位置2之后,会将对象3移动到位置3。
答案 17 :(得分:-1)
有一个非常简单方便的方法来解决问题,而无需任何额外的比较器。只需使用文件名将修改后的日期编码到字符串中,对其进行排序,然后再将其剥离即可。
使用固定长度为20的字符串,将修改后的日期(长)放入其中,并用前导零填充。然后只需将文件名附加到此字符串即可:
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());
这是怎么回事:
文件名1:C:\ data \ file1.html上次修改时间:1532914451455上次修改时间20位:00000001532914451455
文件名1:C:\ data \ file2.html上次修改时间:1532918086822上次修改时间20位:00000001532918086822
将filname转换为:
文件名1:00000001532914451455C:\ data \ file1.html
文件名2:00000001532918086822C:\ data \ file2.html
然后您可以对该列表进行排序。
您需要做的就是稍后再剥离20个字符(在Java 8中,您可以使用.replaceAll函数仅用一行来剥离整个Array)