Javaでファイルをリストする最良の方法は、更新日でソートされていますか?
質問
ディレクトリ内のファイルのリストを取得したいが、最も古いファイルが最初になるようにソートしたい。私の解決策は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());
} });
解決
あなたのソリューションが唯一の賢明な方法だと思います。ファイルのリストを取得する唯一の方法は、 File.listFiles()とドキュメントには、返されるファイルの順序についてこれが保証されないことが記載されています。したがって、使用するコンパレータを記述する必要があります。 File.lastModified()これをファイルの配列とともに Arrays.sort()。
他のヒント
多数のファイルがある場合、これは高速になる可能性があります。これはdecorate-sort-undecorateパターンを使用するため、ソートアルゴリズムが2つのファイルを比較するたびにではなく、各ファイルの最終変更日が once だけでフェッチされます。これにより、I / O呼び出しの数がO(n log n)からO(n)に減少する可能性があります。
ただし、より多くのコードがあるため、これは主に速度に関心があり、実際にはかなり速い場合にのみ使用する必要があります(私はチェックしていません)。
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;
同様のアプローチについてですが、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());
}
});
Java 8以降のエレガントなソリューション:
File[] files = directory.listFiles();
Arrays.sort(files, Comparator.comparingLong(File::lastModified));
または、降順にしたい場合は、単に逆にしてください:
File[] files = directory.listFiles();
Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed());
apache commons IO もご覧ください。組み込みの最終変更コンパレータおよびファイルを操作するための他の多くの素晴らしいユーティリティ。
Java 8の場合:
Arrays.sort(files、(a、b)-&gt; Long.compare(a.lastModified()、b.lastModified()));
インポート:
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);
}
ソートの実行中に、ソート中のファイルを変更または更新できる場合:
Java 8 +
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());
}
}
Java 7
private static List<File> listFilesOldestFirst(final String directoryPath) throws IOException {
final List<File> files = 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 files;
}
これらのソリューションは両方とも、一時的なマップデータ構造を作成して、ディレクトリ内の各ファイルの最終変更時刻を一定に節約します。これを行う必要があるのは、並べ替えの実行中にファイルが更新または変更されると、比較中に最終変更時刻が変更される可能性があるため、コンパレータがコンパレータインターフェイスの一般契約の推移性要件に違反するためです。
一方で、ソート中にファイルが更新または変更されないことがわかっている場合は、この質問に対して送信された他のほとんどの回答を回避できます。
public String[] getDirectoryList(String path) {
String[] dirListing = null;
File dir = new File(path);
dirListing = dir.list();
Arrays.sort(dirListing, 0, dirListing.length);
return dirListing;
}
guava 注文:
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);
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 + "");
}
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;
}
Collections.sort(listFiles, new Comparator<File>() {
public int compare(File f1, File f2) {
return Long.compare(f1.lastModified(), f2.lastModified());
}
});
where listFiles
は、ArrayList内のすべてのファイルのコレクションです
同じ問題を探していたときに 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
}
ありがとう
追加のコンパレータなしで問題を処理する非常に簡単で便利な方法があります。変更された日付をファイル名とともにStringにコーディングし、ソートして、後で再び削除します。
固定長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());
ここで何が起こるか:
Filename1:C:\ data \ file1.html Last Modified:1532914451455 Last Modified 20 Digits:00000001532914451455
Filename1:C:\ data \ file2.html Last Modified:1532918086822 Last Modified 20 Digits:00000001532918086822
filnamesの変換先:
ファイル名1:00000001532914451455C:\ data \ file1.html
ファイル名2:00000001532918086822C:\ data \ file2.html
このリストを並べ替えることができます。
あとで20文字を削除するだけです(Java 8では、.replaceAll関数を使用して、1行だけで配列全体を削除できます)
また、私たちが大きな数を扱っていないので、さらに簡単かもしれない完全に異なる方法があります。
すべてのファイル名とlastModified日付を取得した後に配列全体をソートする代わりに、リストの正しい位置に取得した直後にすべてのファイル名を挿入できます。
次のようにできます:
list.add(1, object1)
list.add(2, object3)
list.add(2, object2)
object2を位置2に追加すると、object3が位置3に移動します。