Freitag, 23. August 2019

Nicht-leere Verzeichnisse löschen

In Java ist es prinizipiell sehr einfach, ein Verzeichnis zu entfernen. Dazu bedient man sich einfach der Methode delete() der Klasse File. Das Problem an dieser Methode ist: Das Verzeichnis muss unbedingt leer sein! Bei einem nicht-leeren Verzeichnis endet diese Methode mit einer Exception. Aber was kann ich tun, um nicht-leere Verzeichnisse zu entfernen? Genau das möchte ich Ihnen in diesem Beitrag erklären.

Rekursives Löschen

Sie können ein Verzeichnis rekursiv löschen. Rekursion bedeutet, dass eine Methode sich selbst immer wieder aufruft. Das nächste Beispiel zeigt eine Methode, die rekursiv ein Verzeichnis und alle enthaltenen Dateien entfernt.

public static void deleteDirectoryRecursion(File file) throws IOException {
  if (file.isDirectory()) {
    File[] entries = file.listFiles();
    if (entries != null) {
      for (File entry : entries) {
        deleteDirectoryRecursion(entry);
      }
    }
  }
  if (!file.delete()) {
    throw new IOException("Failed to delete " + file);
  }
}

Sie sehen in Zeile 6, dass die Methode sich selbst noch einmal aufruft. Was soll das? Stellen Sie sich mal die folgende Ordnerstruktur vor:

- folder1
    -folder2
        -file1
        -file2
    -file3
   
Und jetzt spielen wir den Löschvorgang einmal in Gedanken durch. Wir starten mit folder1 als Übergabeparameter. Wir sehen in dem ersten if, dass es sich um ein Verzeichnis handelt und schnappen uns alle enthaltenen Dateien. Dann laufen wir durch alle enthaltenen Dateien und rufen die Methode deleteDirectoryRecursion() noch einmal mit jeder enthaltenen Datei auf. Die erste Datei ist folder2. Wir machen das gleiche Spiel noch einmal: Wir gehen mit folder2 in diese Methode, erkenen, dass es sich um ein Verzeichnis handelt und rufen für jede Datei einmal die Methode deleteDirectoryRecursion() auf. Wir gehen also mit file1 als Übergabewert in die Methode. file1 ist kein Verzeichnis und wir löschen die Datei. Genauso verfahren wir mit file2. Wir sind am Ende der Aufrufkette angelangt und laufen wieder zurück bis zu dem Methodenaufruf, der fodler2 als Übergabe hatten. Jetzt ist folder2 leer und wir können ihn ganz einfach mit delete() löschen.

Wenn Sie die Methode mal in Gedanken durchspielen, haben Sie das Prinzip schnell verstanden. Bis Java 6 einschließlich gab es keine andere Möglichkeit.

Rekursion mit NIO

Mit Java 7 wurde NIO eingeführt, eine verbesserte API für Dateizugriffe. Mit NIO sieht die ganze Geschichte aus wie folgt:

public static void deleteDirectoryRecursionNio(Path path) throws IOException {
  if (Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS)) {
    try (DirectoryStream<Path> entries = Files.newDirectoryStream(path)) {
      for (Path entry : entries) {
        deleteDirectoryRecursionNio(entry);
      }
    }
  }
  Files.delete(path);

}

Im Prinzip passiert das gleiche wie in dem anderen Rekursionsbeispiel.

Apache Commons IO

Es gibt noch einige weitere Möglichkeit, aber die möchte ich an dieser Stelle mal überspringen und sofort zu der einfachsten Möglichkeit kommen, die allerdings verlangt, dass Sie eine Dritt-API einbinden - nämlich Apache Commons IO. Sie können diese API als jar-Datei herunterladen und in Ihr Projekt einbinden oder bspw. mit Maven arbeiten. Um Apache Commons IO mit Maven einzubinden, fügen Sie einfach den folgenden Code in Ihre pom.xml ein:

<dependency>
   <groupId>commons-io</groupId>
   <artifactId>commons-io</artifactId>
   <version>2.6</version>
</dependency>


Egal wie Sie die Bibliothek in Ihr Programm einbinden, Sie können dann mit dem folgenden ganz einfachen Aufruf ein nicht-leeres Verzeichnis löschen:

FileUtils.delteDirectory(file);

Diese letzte Methode ist natürlich die einfachste Möglichkeit, denn Sie brauchen die unter Umständen fehleranfällige Rekursion nicht mehr selbst zu programmieren und - natürlich - zu testen. Daher empfehle ich diese Möglichkeit, wenn man Dritt-APIs einbinden kann. Die anderen Möglichkeiten sind jedoch ganz schön, um ein wenig mit Rekursion herumzuspielen und sie zu verstehen.

Keine Kommentare:

Kommentar veröffentlichen