Gibt es eine Möglichkeit, ganze Verzeichnisse in Java rekursiv zu löschen?
Im Normalfall ist es möglich, ein leeres Verzeichnis zu löschen. Wenn es jedoch darum geht, ganze Verzeichnisse mit Inhalten zu löschen, ist dies nicht mehr so einfach.
Wie löscht man ganze Verzeichnisse mit Inhalten in Java?
java
file-io
filesystems
delete-directory
paweloque
quelle
quelle
Antworten:
Sie sollten sich Apaches Commons-Io ansehen . Es hat eine FileUtils- Klasse, die macht, was Sie wollen.
quelle
Mit Java 7 können wir dies endlich mit zuverlässiger Symlink-Erkennung erreichen. (Ich halte Apaches Commons-Io derzeit nicht für eine zuverlässige Symlink-Erkennung, da es keine Links unter Windows verarbeitet, die mit erstellt wurden
mklink
.)Aus Gründen der Geschichte finden Sie hier eine Antwort vor Java 7, die auf Symlinks folgt.
quelle
foo
mit einemfoo/link
solchen Link haben ,link->/
wird durch das Aufrufendelete(new File(foo))
so viel von Ihrem Dateisystem gelöscht, wie Ihr Benutzer darf !!In Java 7+ können Sie
Files
class verwenden. Code ist sehr einfach:quelle
super.postVisitDirectory(dir, exc);
IhrepostVisitDirectory
Methode aufrufen , um in die Luft zu jagen, wenn der Spaziergang kein Verzeichnis auflisten konnte.Einzeilige Lösung (Java8) zum rekursiven Löschen aller Dateien und Verzeichnisse einschließlich des Startverzeichnisses:
Wir verwenden einen Komparator für die umgekehrte Reihenfolge, andernfalls kann File :: delete möglicherweise kein nicht leeres Verzeichnis löschen. Wenn Sie also Verzeichnisse behalten und nur Dateien löschen möchten, entfernen Sie einfach den Komparator in sorted () oder entfernen Sie die Sortierung vollständig und fügen Sie den Dateifilter hinzu:
quelle
.sorted(Comparator.reverseOrder())
Der VorschlagComparator::reverseOrder
funktioniert nicht . Siehe: stackoverflow.com/questions/43036611/….sorted((f1, f2) -> f2.compareTo(f1))
, vergleichenf2
mitf1
stattf1
mitf2
.Java 7 hat Unterstützung für Laufverzeichnisse mit Symlink-Behandlung hinzugefügt:
Ich verwende dies als Fallback für plattformspezifische Methoden (in diesem nicht getesteten Code):
(SystemUtils stammt von Apache Commons Lang . Prozesse sind privat, aber ihr Verhalten sollte offensichtlich sein.)
quelle
Ich habe gerade gesehen, dass meine Lösung mehr oder weniger die gleiche ist wie die von Erickson, nur als statische Methode verpackt. Lassen Sie dies irgendwo fallen, es ist viel leichter als die Installation aller Apache Commons für etwas, das (wie Sie sehen können) recht einfach ist.
quelle
Eine Lösung mit einem Stapel und ohne rekursive Methoden:
quelle
list*
Methoden für den Unterrichtjava.io.File
. Aus den Javadocs: "Gibt null zurück, wenn dieser abstrakte Pfadname kein Verzeichnis bezeichnet oder wenn ein E / A-Fehler auftritt." Also:if (currList.length > 0) {
wirdif (null != currList && currList.length > 0) {
Wenn Sie Spring haben, können Sie FileSystemUtils.deleteRecursively verwenden :
quelle
Guave hatte
Files.deleteRecursively(File)
bis Guave 9 unterstützt .Aus Guave 10 :
Daher gibt es in Guava 11 keine solche Methode .
quelle
Oder wenn Sie Folgendes erledigen möchten
IOException
:quelle
Files.walk(path).iterator().toSeq.reverse.foreach(Files.delete)
walk
Methode garantiert bereits eine Tiefenüberquerung.Collections.reverseOrder()
sodass Ihr Code davonfor (Path p : Files.walk(directoryToDelete).sorted(reverseOrder()).toArray(Path[]::new))
ausgeht, dass er statisch importiert wurde.Comparator.reverseOrder
?Files.walk(dir) .sorted(Comparator.reverseOrder()) .toArray(Path[]::new))
quelle
quelle
f.delete()
unterdeleteDirectory(f)
löst NoSuchFileException aus, dadeleteDirectory(f)
diese Datei bereits gelöscht wird. Jedes Verzeichnis wird zu einem Pfad, wenn es übergebendeleteDirectory(f)
und von gelöscht wirdpath.delete()
. Daher brauchen wirf.delete()
inif f.isDerectory
Abschnitt nicht. Also einfachf.delete();
unter deleteDirectory (f) löschen und es wird funktionieren.Zwei Möglichkeiten, mit Symlinks und dem obigen Code zu scheitern ... und die Lösung nicht zu kennen.
Weg # 1
Führen Sie dies aus, um einen Test zu erstellen:
Hier sehen Sie Ihre Testdatei und Ihr Testverzeichnis:
Führen Sie dann Ihr commons-io deleteDirectory () aus. Es stürzt ab und die Datei wird nicht gefunden. Ich bin mir nicht sicher, was die anderen Beispiele hier tun. Der Linux-Befehl rm löscht einfach den Link und rm -r im Verzeichnis auch.
Weg # 2
Führen Sie dies aus, um einen Test zu erstellen:
Hier sehen Sie Ihre Testdatei und Ihr Testverzeichnis:
Führen Sie dann Ihr commons-io deleteDirectory () oder den von Personen geposteten Beispielcode aus. Es löscht nicht nur das Verzeichnis, sondern auch Ihre Testdatei, die sich außerhalb des zu löschenden Verzeichnisses befindet. (Das Verzeichnis wird implizit dereferenziert und der Inhalt gelöscht.) rm -r würde nur den Link löschen. Sie müssen so etwas verwenden, um die dereferenzierten Dateien zu löschen: "find -L mudodelete -type f -exec rm {} \;".
quelle
Du könntest benutzen:
org.apache.commons.io.FileUtils.deleteQuietly(destFile);
Löscht eine Datei und löst niemals eine Ausnahme aus. Wenn es sich bei der Datei um ein Verzeichnis handelt, löschen Sie es und alle Unterverzeichnisse. Der Unterschied zwischen File.delete () und dieser Methode besteht darin, dass ein zu löschendes Verzeichnis nicht leer sein muss. Es werden keine Ausnahmen ausgelöst, wenn eine Datei oder ein Verzeichnis nicht gelöscht werden kann.
quelle
Eine optimale Lösung, die Ausnahmen konsistent mit dem Ansatz behandelt, dass eine von einer Methode ausgelöste Ausnahme immer beschreiben sollte, was diese Methode versucht hat (und was nicht):
quelle
In älteren Projekten muss ich nativen Java-Code erstellen. Ich erstelle diesen Code ähnlich dem Paulitex-Code. Siehst du das:
Und der Unit Test:
quelle
Der folgende Code löscht rekursiv alle Inhalte in einem bestimmten Ordner.
quelle
Hier ist eine Bare-Bones-Hauptmethode, die ein Befehlszeilenargument akzeptiert. Möglicherweise müssen Sie Ihre eigene Fehlerprüfung anhängen oder sie nach Ihren Wünschen anpassen.
Ich hoffe das hilft!
quelle
Möglicherweise besteht eine Lösung für dieses Problem darin, die Löschmethode der File-Klasse mithilfe des Codes aus Ericksons Antwort erneut zu implementieren:
quelle
Ohne Commons IO und <Java SE 7
quelle
Während Dateien einfach mit file.delete () gelöscht werden können, müssen Verzeichnisse leer sein, um gelöscht zu werden. Verwenden Sie die Rekursion, um dies einfach zu tun. Zum Beispiel:
quelle
Ich habe diese Routine codiert, die 3 Sicherheitskriterien für eine sicherere Verwendung hat.
quelle
Nehmen wir ein Beispiel an:
Weitere Informationen finden Sie unter Ressourcen
Verzeichnis löschen
quelle
rm -rf
war viel performanter alsFileUtils.deleteDirectory
.Nach ausgiebigem Benchmarking stellten wir fest, dass die Verwendung
rm -rf
um ein Vielfaches schneller war als die VerwendungFileUtils.deleteDirectory
.Wenn Sie ein kleines oder einfaches Verzeichnis haben, spielt das natürlich keine Rolle, aber in unserem Fall hatten wir mehrere Gigabyte und tief verschachtelte Unterverzeichnisse, in denen es mehr als 10 Minuten
FileUtils.deleteDirectory
und nur 1 Minute dauern würderm -rf
.Hier ist unsere grobe Java-Implementierung, um dies zu tun:
Es lohnt sich zu versuchen, wenn Sie mit großen oder komplexen Verzeichnissen arbeiten.
quelle
Guave bietet einen Einzeiler :
MoreFiles.deleteRecursively()
.Im Gegensatz zu vielen der freigegebenen Beispiele werden symbolische Links berücksichtigt und Dateien (außerhalb des angegebenen Pfads) werden (standardmäßig) nicht gelöscht.
quelle