Ich habe diese Funktion, die den Namen aller Dateien in einem Verzeichnis rekursiv druckt. Das Problem ist, dass mein Code sehr langsam ist, da er bei jeder Iteration auf ein Remote-Netzwerkgerät zugreifen muss.
Mein Plan ist es, zuerst alle Dateien rekursiv aus dem Verzeichnis zu laden und danach alle Dateien mit dem regulären Ausdruck durchzugehen, um alle Dateien herauszufiltern, die ich nicht möchte. Hat jemand einen besseren Vorschlag?
public static printFnames(String sDir){
File[] faFiles = new File(sDir).listFiles();
for(File file: faFiles){
if(file.getName().matches("^(.*?)")){
System.out.println(file.getAbsolutePath());
}
if(file.isDirectory()){
printFnames(file.getAbsolutePath());
}
}
}
Dies ist nur ein Test später. Ich werde den Code nicht so verwenden, sondern den Pfad und das Änderungsdatum jeder Datei hinzufügen, die einem erweiterten regulären Ausdruck zu einem Array entspricht.
Antworten:
Angenommen, dies ist der tatsächliche Produktionscode, den Sie schreiben, dann schlage ich vor, die Lösung für diese Art von Dingen zu verwenden, die bereits gelöst wurden - speziell Apache Commons IO
FileUtils.listFiles()
. Es behandelt verschachtelte Verzeichnisse, Filter (basierend auf Name, Änderungszeit usw.).Zum Beispiel für Ihre Regex:
Dadurch wird rekursiv nach Dateien gesucht, die dem
^(.*?)
regulären Ausdruck entsprechen, und die Ergebnisse werden als Sammlung zurückgegeben.Es ist erwähnenswert, dass dies nicht schneller ist als das Rollen Ihres eigenen Codes. Es macht dasselbe - das Durchsuchen eines Dateisystems in Java ist nur langsam. Der Unterschied ist, dass die Apache Commons-Version keine Fehler enthält.
quelle
Files.walk(Paths.get("/etc")).filter(Files::isRegularFile).collect(Collectors.toList())
In Java 8 handelt es sich um einen 1-Liner-Via
Files.find()
mit einer beliebig großen Tiefe (z. B.999
) undBasicFileAttributes
vonisRegularFile()
Um weitere Filter hinzuzufügen, verbessern Sie das Lambda, z. B. alle in den letzten 24 Stunden geänderten JPG-Dateien:
quelle
Dies ist eine sehr einfache rekursive Methode, um alle Dateien von einem bestimmten Stamm abzurufen.
Es verwendet die Java 7 NIO Path-Klasse.
quelle
Mit Java 7 wurde eine schnellere Möglichkeit zum Durchlaufen eines Verzeichnisbaums mit der
Paths
undFiles
-Funktionalität eingeführt. Sie sind viel schneller als der "alte"File
Weg.Dies wäre der Code zum Durchlaufen und Überprüfen der Pfadnamen mit einem regulären Ausdruck:
quelle
Der schnelle Weg, um den Inhalt eines Verzeichnisses mit Java 7 NIO abzurufen:
quelle
Files.newDirectoryStream
kann eine IOException auslösen. Ich schlage vor, diese Zeile in eine Java7-Try-with-Anweisung zu verpacken, damit der Stream für Sie immer geschlossen bleibt (Ausnahme oder nicht, ohne dass ein a erforderlich istfinally
). Siehe auch hier: stackoverflow.com/questions/17739362/…Die Java-Oberfläche zum Lesen von Ordnerinhalten im Dateisystem ist nicht sehr leistungsfähig (wie Sie festgestellt haben). JDK 7 behebt dieses Problem mit einer völlig neuen Schnittstelle für diese Art von Dingen, die die Leistung auf nativer Ebene für diese Art von Vorgängen verbessern soll.
Das Hauptproblem besteht darin, dass Java für jede einzelne Datei einen nativen Systemaufruf ausführt. Auf einer Schnittstelle mit geringer Latenz ist dies keine große Sache - aber in einem Netzwerk mit selbst mäßiger Latenz summiert sich das wirklich. Wenn Sie Ihren Algorithmus oben profilieren, werden Sie feststellen, dass der Großteil der Zeit im lästigen Aufruf von isDirectory () verbracht wird. Dies liegt daran, dass Sie für jeden einzelnen Aufruf von isDirectory () einen Roundtrip durchführen. Die meisten modernen Betriebssysteme können diese Art von Informationen bereitstellen, wenn die Liste der Dateien / Ordner ursprünglich angefordert wurde (anstatt jeden einzelnen Dateipfad nach seinen Eigenschaften abzufragen).
Wenn Sie nicht auf JDK7 warten können, besteht eine Strategie zur Behebung dieser Latenz darin, Multithreading zu verwenden und einen ExecutorService mit einer maximalen Anzahl von Threads zu verwenden, um Ihre Rekursion durchzuführen. Es ist nicht großartig (Sie müssen sich mit dem Sperren Ihrer Ausgabedatenstrukturen befassen), aber es wird verdammt viel schneller sein als dieses einzelne Threaded.
In all Ihren Diskussionen über diese Art von Dingen empfehle ich Ihnen dringend, sich mit dem Besten zu vergleichen, das Sie mit nativem Code (oder sogar einem Befehlszeilenskript, das ungefähr dasselbe tut) tun können. Zu sagen, dass das Durchqueren einer Netzwerkstruktur eine Stunde dauert, bedeutet nicht wirklich viel. Wenn Sie uns sagen, dass Sie es in 7 Sekunden nativ machen können, aber in Java dauert es eine Stunde, wird die Aufmerksamkeit der Leute auf sich gezogen.
quelle
Dies wird gut funktionieren ... und es ist rekursiv
quelle
Ich persönlich mag diese Version von FileUtils. Hier ist ein Beispiel, das alle MP3s oder Flacs in einem Verzeichnis oder einem seiner Unterverzeichnisse findet:
quelle
Dies wird gut funktionieren
quelle
Diese Funktion listet wahrscheinlich den gesamten Dateinamen und den Pfad aus dem Verzeichnis und den Unterverzeichnissen auf.
quelle
Dein Gefühl ist falsch. So funktionieren Dateisysteme. Es gibt keinen schnelleren Weg (außer wenn Sie dies wiederholt oder für verschiedene Muster tun müssen, können Sie alle Dateipfade im Speicher zwischenspeichern, aber dann müssen Sie sich mit der Ungültigmachung des Caches befassen, dh was passiert, wenn Dateien hinzugefügt / entfernt / umbenannt werden die App läuft).
quelle
Nur damit Sie wissen, dass isDirectory () eine ziemlich langsame Methode ist. Ich finde es ziemlich langsam in meinem Dateibrowser. Ich werde in eine Bibliothek schauen, um sie durch nativen Code zu ersetzen.
quelle
Der effizientere Weg, mit Millionen von Ordnern und Dateien umzugehen, besteht darin, die Verzeichnisliste mit dem DOS-Befehl in einer Datei zu erfassen und zu analysieren. Sobald Sie die Daten analysiert haben, können Sie Analysen durchführen und Statistiken berechnen.
quelle
quelle
In Guava müssen Sie nicht auf die Rückgabe einer Sammlung warten, sondern können die Dateien tatsächlich durchlaufen. Es ist leicht, sich eine
IDoSomethingWithThisFile
Schnittstelle in der Signatur der folgenden Funktion vorzustellen :Mit TreeTraverser können Sie auch zwischen verschiedenen Durchlaufstilen wechseln .
quelle
Java 8
quelle
quelle
Ein weiterer optimierter Code
quelle
Ein weiteres Beispiel für das Auflisten von Dateien und Verzeichnissen mit Java 8
filter
quelle