Löschen Sie Verzeichnisse rekursiv in Java


382

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?


4
File.delete () sollte beim Aufruf mit einem nicht leeren Verzeichnis einfach false zurückgeben.
Ben S

Wenn Sie Java 8 verwenden, lesen Sie die Antwort von @ RoK.
Robin

Antworten:


462

Sie sollten sich Apaches Commons-Io ansehen . Es hat eine FileUtils- Klasse, die macht, was Sie wollen.

FileUtils.deleteDirectory(new File("directory"));

3
Diese Funktion umschließt wahrscheinlich den Code, den erickson in seiner Antwort angegeben hat.
paweloque

14
Es ist etwas gründlicher. Es behandelt Dinge wie symbolische Links unter Linux / Unix korrekt. svn.apache.org/viewvc/commons/proper/io/trunk/src/java/org/…
Steve K



Warum eine weitere Abhängigkeit hinzufügen, wenn Java über eine sofort einsatzbereite Funktion verfügt? Siehe Antwort von RoK auf dieser Seite oder stackoverflow.com/questions/35988192/…
foo

190

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.

void delete(File f) throws IOException {
  if (f.isDirectory()) {
    for (File c : f.listFiles())
      delete(c);
  }
  if (!f.delete())
    throw new FileNotFoundException("Failed to delete file: " + f);
}

11
File.delete () verfügt nicht über diese Funktionalität.
Ben S

14
@Erickson: Ist FileNotFoundException nicht eine schlechte Ausnahme für einen Löschfehler? Wenn die Datei wirklich nicht mehr vorhanden ist, muss sie bereits gelöscht worden sein, was bedeutet, dass das Löschen semantisch nicht fehlgeschlagen ist - es hatte nichts zu tun. Und wenn es aus einem anderen Grund fehlschlug, lag es nicht daran, dass die Datei nicht gefunden wurde.
Lawrence Dol

46
Seien Sie sehr vorsichtig . Dadurch werden Symlinks dereferenziert. Wenn Sie zB unter Linux arbeiten und einen Ordner foomit einem foo/linksolchen Link haben , link->/wird durch das Aufrufen delete(new File(foo)) so viel von Ihrem Dateisystem gelöscht, wie Ihr Benutzer darf !!
Miquel

4
@Miquel Das macht keinen Sinn - Warum sollten wir vorsichtig sein wollen? Der Sinn des bereitgestellten Codes besteht sicherlich darin, ein gesamtes Verzeichnis zu entfernen, wie es scheint. Ich verstehe nicht, was die Gefahr hier ist.
Joehot200

12
@ Joehot200 Sie haben Recht, wenn Sie delete für einen Verzeichnissymlink aufrufen, wird das Verzeichnis nicht gelöscht, sondern nur der Symlink selbst. Zum Löschen des Verzeichnisses müsste der Symlink explizit mit ReadSymbolicLink befolgt werden . Mein Fehler! Gut entdeckt
Miquel

148

In Java 7+ können Sie Filesclass verwenden. Code ist sehr einfach:

Path directory = Paths.get("/tmp");
Files.walkFileTree(directory, new SimpleFileVisitor<Path>() {
   @Override
   public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
       Files.delete(file);
       return FileVisitResult.CONTINUE;
   }

   @Override
   public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
       Files.delete(dir);
       return FileVisitResult.CONTINUE;
   }
});

2
Diese Lösung wirkt sehr elegant und enthält überhaupt keine Verzeichnisüberquerungslogik!
Zero3

1
"Um eine Perle zu finden, tauchen Sie tief in den Ozean ein." Dies ist bei weitem die sauberste Lösung, die ich gefunden habe. Musste tief tauchen, um es zu finden. Brillant!
Basil Musa

20
"Code ist" NICHT "sehr einfach", um einfach ein Verzeichnis zu löschen :-) Aber hey, das ist meiner Meinung nach die beste Lösung in reinem Java.
Mat

1
Bitte beachten Sie, dass die hier verwendete walkFileTree-Überladung " keinen symbolischen Links folgt ". (Javadoc: docs.oracle.com/javase/7/docs/api/java/nio/file/… )
Stephan

1
Sie sollten wahrscheinlich super.postVisitDirectory(dir, exc);Ihre postVisitDirectoryMethode aufrufen , um in die Luft zu jagen, wenn der Spaziergang kein Verzeichnis auflisten konnte.
Tom Anderson

68

Einzeilige Lösung (Java8) zum rekursiven Löschen aller Dateien und Verzeichnisse einschließlich des Startverzeichnisses:

Files.walk(Paths.get("c:/dir_to_delete/"))
                .map(Path::toFile)
                .sorted((o1, o2) -> -o1.compareTo(o2))
                .forEach(File::delete);

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:

Files.walk(Paths.get("c:/dir_to_delete/"))
                .filter(Files::isRegularFile)
                .map(Path::toFile)
                .forEach(File::delete);

1
Sie müssen die Sortierung in der ersten in .sorted (Comparator :: reverseOrder) ändern , um alle Verzeichnisse zu löschen. Andernfalls wird das übergeordnete Verzeichnis vor dem untergeordneten Verzeichnis angeordnet und daher nicht gelöscht, da es nicht leer ist. Tolle Antwort für diejenigen, die Java 8 verwenden!
Robin

1
Der richtige Weg ist .sorted(Comparator.reverseOrder())Der Vorschlag Comparator::reverseOrderfunktioniert nicht . Siehe: stackoverflow.com/questions/43036611/…
user1156544

4
Robin, achte auf das Minuszeichen in "-o1.compareTo (o2)". Es ist das gleiche wie .sorted (Comparator.reverseOrder)
RoK

Ist Files.walk sequentiell? Oder benötigt diese Antwort forEachOrdered anstelle von forEach, um zu vermeiden, dass versucht wird, nicht leere Verzeichnisse zu löschen?
Silwing

Verwenden Sie einfach : .sorted((f1, f2) -> f2.compareTo(f1)), vergleichen f2mit f1statt f1mit f2.
Beto Neto

67

Java 7 hat Unterstützung für Laufverzeichnisse mit Symlink-Behandlung hinzugefügt:

import java.nio.file.*;

public static void removeRecursive(Path path) throws IOException
{
    Files.walkFileTree(path, new SimpleFileVisitor<Path>()
    {
        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                throws IOException
        {
            Files.delete(file);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException
        {
            // try to delete the file anyway, even if its attributes
            // could not be read, since delete-only access is
            // theoretically possible
            Files.delete(file);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException
        {
            if (exc == null)
            {
                Files.delete(dir);
                return FileVisitResult.CONTINUE;
            }
            else
            {
                // directory iteration failed; propagate exception
                throw exc;
            }
        }
    });
}

Ich verwende dies als Fallback für plattformspezifische Methoden (in diesem nicht getesteten Code):

public static void removeDirectory(Path directory) throws IOException
{
    // does nothing if non-existent
    if (Files.exists(directory))
    {
        try
        {
            // prefer OS-dependent directory removal tool
            if (SystemUtils.IS_OS_WINDOWS)
                Processes.execute("%ComSpec%", "/C", "RD /S /Q \"" + directory + '"');
            else if (SystemUtils.IS_OS_UNIX)
                Processes.execute("/bin/rm", "-rf", directory.toString());
        }
        catch (ProcessExecutionException | InterruptedException e)
        {
            // fallback to internal implementation on error
        }

        if (Files.exists(directory))
            removeRecursive(directory);
    }
}

(SystemUtils stammt von Apache Commons Lang . Prozesse sind privat, aber ihr Verhalten sollte offensichtlich sein.)


Ich finde ein Problem mit Files.walkFileTree - es reicht nicht aus, um eine Version des rekursiven Löschens zu implementieren, bei der Sie Dateien so lange löschen, bis Ihnen die Optionen ausgehen. Es ist ausreichend für eine Fail-Fast-Version, aber Fail-Fast ist nicht immer das, was Sie wollen (z. B. wenn Sie temporäre Dateien
bereinigen

Ich verstehe nicht, warum das so ist. Sie können Fehler nach Belieben behandeln - Sie müssen nicht schnell ausfallen. Das einzige Problem, das ich vorhersehen konnte, ist, dass möglicherweise keine neuen Dateien verarbeitet werden, die während des Durchlaufs des aktuellen Verzeichnisses erstellt werden. Dies ist jedoch eine einzigartige Situation, die besser für eine benutzerdefinierte Lösung geeignet ist.
Trevor Robinson

1
Wenn Sie den Fehler von visitFile unterdrücken und walkFileTree für eine einzelne Datei aufrufen, die fehlschlägt, wird kein Fehler angezeigt (visitFile muss daher alle auftretenden Fehler weitergeben.) Wenn Sie ein Verzeichnis löschen und eine Datei nicht löschen, wird der einzige Rückruf aufgerufen ist postVisitDirectory. Das heißt, es werden die anderen Dateien im Verzeichnis nicht besucht, wenn beim Aufrufen einer Datei ein Fehler auftritt. Das ist was ich meine. Ich bin mir sicher, dass es wahrscheinlich eine Möglichkeit gibt, dies zu umgehen, aber als wir an diesem Punkt angelangt waren, hatten wir bereits mehr Code als eine herkömmliche rekursive Löschroutine geschrieben, sodass wir uns gegen die Verwendung entschieden haben.
Trejkaz

Vielen Dank für Ihren ersten Code, er war nützlich für mich, aber ich musste ihn ändern, da er keinen einfachen Deltree vervollständigte: Ich musste die Ausnahme in "postVisitDirectory" ignorieren und CONTINUE zurückgeben, unabhängig davon, ob der folgende einfache Baum nicht vollständig konnte gelöscht werden: Ein Verzeichnis, in dem sich ein anderes Verzeichnis befand, in dem sich eine Datei befand. Alles so einfach / normal wie es nur geht, unter Windows.
Dreamspace Präsident

Alles begann mit einer java.nio.file.DirectoryNotEmptyException, die ich bekam. Ich habe den Fall herausgefunden, in dem visitFileFailed verwendet wird. Wenn Ihre Verzeichnisstruktur in Windows einen Link vom Typ Junction enthält. Dies kann zu 2 Problemen führen: *) Files.walkFileTree folgt dem Link in die Junction und löscht dort alles. *) Wenn das Junction-Zielverzeichnis bereits gelöscht ist, schlägt das Parsen des Links durch Files.walkFileTree mit NoSuchFileException fehl, die in visitFileFailed abgefangen wird.
Andres Luuk

34

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.

public class FileUtils {
    /**
     * By default File#delete fails for non-empty directories, it works like "rm". 
     * We need something a little more brutual - this does the equivalent of "rm -r"
     * @param path Root File Path
     * @return true iff the file and all sub files/directories have been removed
     * @throws FileNotFoundException
     */
    public static boolean deleteRecursive(File path) throws FileNotFoundException{
        if (!path.exists()) throw new FileNotFoundException(path.getAbsolutePath());
        boolean ret = true;
        if (path.isDirectory()){
            for (File f : path.listFiles()){
                ret = ret && deleteRecursive(f);
            }
        }
        return ret && path.delete();
    }
}

20

Eine Lösung mit einem Stapel und ohne rekursive Methoden:

File dir = new File("/path/to/dir");
File[] currList;
Stack<File> stack = new Stack<File>();
stack.push(dir);
while (! stack.isEmpty()) {
    if (stack.lastElement().isDirectory()) {
        currList = stack.lastElement().listFiles();
        if (currList.length > 0) {
            for (File curr: currList) {
                stack.push(curr);
            }
        } else {
            stack.pop().delete();
        }
    } else {
        stack.pop().delete();
    }
}

2
+1 für die Verwendung eines Stapels. Dies funktioniert mit Verzeichnissen, die tiefe Ebenen verschachtelter Unterverzeichnisse enthalten, während die anderen stapelbasierten Ansätze fehlschlagen.
Nathan Osman

4
Angesichts der Tatsache, dass Sie normalerweise keine Probleme haben, ein paar hundert Methodenaufrufe zu verschachteln, werden Sie wahrscheinlich viel früher auf Dateisystembeschränkungen stoßen.
Bombe

2
Seien Sie vorsichtig mit den list*Methoden für den Unterricht java.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) {
Kevinarpe

1
Ich verwende ein ArrayDeque anstelle eines Stacks, der etwas schneller ist. (nicht synchronisiert)
Wytze


15

Guave hatte Files.deleteRecursively(File)bis Guave 9 unterstützt .

Aus Guave 10 :

Veraltet. Diese Methode leidet unter einer schlechten Symlink-Erkennung und schlechten Rennbedingungen. Diese Funktionalität kann nur durch Ausgeben an einen Betriebssystembefehl wie rm -rfoder in geeigneter Weise unterstützt werden del /s. Diese Methode soll in Guava Release 11.0 aus Guava entfernt werden.

Daher gibt es in Guava 11 keine solche Methode .


6
Schade. Das Beschießen scheint ein wenig grob und nicht tragbar. Wenn die Apache Commons-Version ordnungsgemäß funktioniert, ist die Implementierung vermutlich nicht unmöglich.
Andrew McKinlay

6
@andrew Die Apache Commons-Implementierung sollte ähnliche Probleme haben wie diejenigen, die dazu führen, dass Guava ihre Implementierung entfernt. Siehe code.google.com/p/guava-libraries/issues/detail?id=365
orip

Die Apache Commons-Version erkennt Symlinks und durchläuft die untergeordneten Elemente der Datei einfach nicht.
Ajax

5
Guava 21.0 fügte dies als MoreFiles.deleteRecursively () hinzu .
Robert Fleming

12
for(Path p : Files.walk(directoryToDelete).
        sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
        toArray(Path[]::new))
{
    Files.delete(p);
}

Oder wenn Sie Folgendes erledigen möchten IOException:

Files.walk(directoryToDelete).
    sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
    forEach(p -> {
        try { Files.delete(p); }
        catch(IOException e) { /* ... */ }
      });

2
Dies half mir, eine Scala-Version zu entwickeln:Files.walk(path).iterator().toSeq.reverse.foreach(Files.delete)
James Ward

Ist eine Sortierung wirklich notwendig? Die walkMethode garantiert bereits eine Tiefenüberquerung.
VGR

Der Komparator könnte recycelt werden, Collections.reverseOrder()sodass Ihr Code davon for (Path p : Files.walk(directoryToDelete).sorted(reverseOrder()).toArray(Path[]::new))ausgeht, dass er statisch importiert wurde.
namero999

@ namero999 Meinst du Comparator.reverseOrder? Files.walk(dir) .sorted(Comparator.reverseOrder()) .toArray(Path[]::new))
Jeff

@ Jeff ziemlich sicher, dass Sie Recht haben, ging meistens aus dem Gedächtnis dort :)
namero999

11
public void deleteRecursive(File path){
    File[] c = path.listFiles();
    System.out.println("Cleaning out folder:" + path.toString());
    for (File file : c){
        if (file.isDirectory()){
            System.out.println("Deleting file:" + file.toString());
            deleteRecursive(file);
            file.delete();
        } else {
            file.delete();
        }
    }
    path.delete();
}

5
Erweiterte Version mit booleschem Rückgabewert und ohne Duplizierung: pastebin.com/PqJyzQUx
Erik Kaplun

9
static public void deleteDirectory(File path) 
{
    if (path == null)
        return;
    if (path.exists())
    {
        for(File f : path.listFiles())
        {
            if(f.isDirectory()) 
            {
                deleteDirectory(f);
                f.delete();
            }
            else
            {
                f.delete();
            }
        }
        path.delete();
    }
}

Netter Code, aber es gibt einen Fehler, der behoben ist, wenn er behoben ist. Die Zeile f.delete()unter deleteDirectory(f)löst NoSuchFileException aus, da deleteDirectory(f)diese Datei bereits gelöscht wird. Jedes Verzeichnis wird zu einem Pfad, wenn es übergeben deleteDirectory(f)und von gelöscht wird path.delete(). Daher brauchen wir f.delete()in if f.isDerectoryAbschnitt nicht. Also einfach f.delete();unter deleteDirectory (f) löschen und es wird funktionieren.
Trieu Nguyen

5

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:

echo test > testfile
mkdir dirtodelete
ln -s badlink dirtodelete/badlinktodelete

Hier sehen Sie Ihre Testdatei und Ihr Testverzeichnis:

$ ls testfile dirtodelete
testfile

dirtodelete:
linktodelete

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.

Exception in thread "main" java.io.FileNotFoundException: File does not exist: /tmp/dirtodelete/linktodelete

Weg # 2

Führen Sie dies aus, um einen Test zu erstellen:

mkdir testdir
echo test > testdir/testfile
mkdir dirtodelete
ln -s ../testdir dirtodelete/dirlinktodelete

Hier sehen Sie Ihre Testdatei und Ihr Testverzeichnis:

$ ls dirtodelete testdir
dirtodelete:
dirlinktodelete

testdir:
testfile

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 {} \;".

$ ls dirtodelete testdir
ls: cannot access dirtodelete: No such file or directory
testdir:

4

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.


4

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):

private void deleteRecursive(File f) throws Exception {
    try {
        if (f.isDirectory()) {
            for (File c : f.listFiles()) {
                deleteRecursive(c);
            }
        }
        if (!f.delete()) {
            throw new Exception("Delete command returned false for file: " + f);
        }
    } 
    catch (Exception e) {
        throw new Exception("Failed to delete the folder: " + f, e);
    }
}

3

In älteren Projekten muss ich nativen Java-Code erstellen. Ich erstelle diesen Code ähnlich dem Paulitex-Code. Siehst du das:

public class FileHelper {

   public static boolean delete(File fileOrFolder) {
      boolean result = true;
      if(fileOrFolder.isDirectory()) {
         for (File file : fileOrFolder.listFiles()) {
            result = result && delete(file);
         }
      }
      result = result && fileOrFolder.delete();
      return result;
   } 
}

Und der Unit Test:

public class FileHelperTest {

    @Before
    public void setup() throws IOException {
       new File("FOLDER_TO_DELETE/SUBFOLDER").mkdirs();
       new File("FOLDER_TO_DELETE/SUBFOLDER_TWO").mkdirs();
       new File("FOLDER_TO_DELETE/SUBFOLDER_TWO/TEST_FILE.txt").createNewFile();
    }

    @Test
    public void deleteFolderWithFiles() {
       File folderToDelete = new File("FOLDER_TO_DELETE");
       Assert.assertTrue(FileHelper.delete(folderToDelete));
       Assert.assertFalse(new File("FOLDER_TO_DELETE").exists());
    }

}

3

Der folgende Code löscht rekursiv alle Inhalte in einem bestimmten Ordner.

boolean deleteDirectory(File directoryToBeDeleted) {
    File[] allContents = directoryToBeDeleted.listFiles();
    if (allContents != null) {
        for (File file : allContents) {
            deleteDirectory(file);
        }
    }
    return directoryToBeDeleted.delete();
}

2

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.

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

public class DeleteFiles {

/**
 * @param intitial arguments take in a source to read from and a 
 * destination to read to
 */
    public static void main(String[] args)
                     throws FileNotFoundException,IOException {
        File src = new File(args[0]);
        if (!src.exists() ) {
            System.out.println("FAILURE!");
        }else{
            // Gathers files in directory
            File[] a = src.listFiles();
            for (int i = 0; i < a.length; i++) {
                //Sends files to recursive deletion method
                fileDelete(a[i]);
            }
            // Deletes original source folder
            src.delete();
            System.out.println("Success!");
        }
    }

    /**
     * @param srcFile Source file to examine
     * @throws FileNotFoundException if File not found
     * @throws IOException if File not found
     */
    private static void fileDelete(File srcFile)
                     throws FileNotFoundException, IOException {
        // Checks if file is a directory
        if (srcFile.isDirectory()) {
            //Gathers files in directory
            File[] b = srcFile.listFiles();
            for (int i = 0; i < b.length; i++) {
                //Recursively deletes all files and sub-directories
                fileDelete(b[i]);
            }
            // Deletes original sub-directory file
            srcFile.delete();
        } else {
            srcFile.delete();
        }
    }
}

Ich hoffe das hilft!


1

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:

public class MyFile extends File {

  ... <- copy constructor

  public boolean delete() {
    if (f.isDirectory()) {
      for (File c : f.listFiles()) {
        return new MyFile(c).delete();
      }
    } else {
        return f.delete();
    }
  }
}

1
Ich denke, es ist so implementiert, dass es das Verhalten der meisten Befehls-Shell-Dienstprogramme wie "rm", "rmdir" und "del" nachahmt. Von den beiden Alternativen minimiert die aktuelle Implementierung definitiv das allgemeine Überraschungs- (und Wut-) Potenzial. Es wird sich nicht ändern.
Erickson

4
Im Allgemeinen sind die einzigen Java JRE-Pakete, die ich erweitert sehe, von Swing. Normalerweise ist das Erweitern anderer Klassen wie java.io.File eine schlechte Idee, da es die Möglichkeit gibt, dass Dinge auf unerwartete Weise wirken.
Eddie

1

Ohne Commons IO und <Java SE 7

public static void deleteRecursive(File path){
            path.listFiles(new FileFilter() {
                @Override
                public boolean accept(File pathname) {
                    if (pathname.isDirectory()) {
                        pathname.listFiles(this);
                        pathname.delete();
                    } else {
                        pathname.delete();
                    }
                    return false;
                }
            });
            path.delete();
        }

0

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:

public static void clearFolders(String[] args) {
        for(String st : args){
            File folder = new File(st);
            if (folder.isDirectory()) {
                File[] files = folder.listFiles();
                if(files!=null) { 
                    for(File f: files) {
                        if (f.isDirectory()){
                            clearFolders(new String[]{f.getAbsolutePath()});
                            f.delete();
                        } else {
                            f.delete();
                        }
                    }
                }
            }
        }
    }

0

Ich habe diese Routine codiert, die 3 Sicherheitskriterien für eine sicherere Verwendung hat.

package ch.ethz.idsc.queuey.util;

import java.io.File;
import java.io.IOException;

/** recursive file/directory deletion
 * 
 * safety from erroneous use is enhanced by three criteria
 * 1) checking the depth of the directory tree T to be deleted
 * against a permitted upper bound "max_depth"
 * 2) checking the number of files to be deleted #F
 * against a permitted upper bound "max_count"
 * 3) if deletion of a file or directory fails, the process aborts */
public final class FileDelete {
    /** Example: The command
     * FileDelete.of(new File("/user/name/myapp/recordings/log20171024"), 2, 1000);
     * deletes given directory with sub directories of depth of at most 2,
     * and max number of total files less than 1000. No files are deleted
     * if directory tree exceeds 2, or total of files exceed 1000.
     * 
     * abort criteria are described at top of class
     * 
     * @param file
     * @param max_depth
     * @param max_count
     * @return
     * @throws Exception if criteria are not met */
    public static FileDelete of(File file, int max_depth, int max_count) throws IOException {
        return new FileDelete(file, max_depth, max_count);
    }

    // ---
    private final File root;
    private final int max_depth;
    private int removed = 0;

    /** @param root file or a directory. If root is a file, the file will be deleted.
     *            If root is a directory, the directory tree will be deleted.
     * @param max_depth of directory visitor
     * @param max_count of files to delete
     * @throws IOException */
    private FileDelete(final File root, final int max_depth, final int max_count) throws IOException {
        this.root = root;
        this.max_depth = max_depth;
        // ---
        final int count = visitRecursively(root, 0, false);
        if (count <= max_count) // abort criteria 2)
            visitRecursively(root, 0, true);
        else
            throw new IOException("more files to be deleted than allowed (" + max_count + "<=" + count + ") in " + root);
    }

    private int visitRecursively(final File file, final int depth, final boolean delete) throws IOException {
        if (max_depth < depth) // enforce depth limit, abort criteria 1)
            throw new IOException("directory tree exceeds permitted depth");
        // ---
        int count = 0;
        if (file.isDirectory()) // if file is a directory, recur
            for (File entry : file.listFiles())
                count += visitRecursively(entry, depth + 1, delete);
        ++count; // count file as visited
        if (delete) {
            final boolean deleted = file.delete();
            if (!deleted) // abort criteria 3)
                throw new IOException("cannot delete " + file.getAbsolutePath());
            ++removed;
        }
        return count;
    }

    public int deletedCount() {
        return removed;
    }

    public void printNotification() {
        int count = deletedCount();
        if (0 < count)
            System.out.println("deleted " + count + " file(s) in " + root);
    }
}

0

Nehmen wir ein Beispiel an:

import java.io.File;
import java.io.IOException;

public class DeleteDirectory
{
   private static final String folder = "D:/project/java";

   public static void main(String[] args) throws IOException
   {
      File fl = new File(folder);
      if(!fl.exists()) // checking if directory exists
      {
         System.out.println("Sorry!! directory doesn't exist.");
      }
      else
      {
         DeleteDirectory dd = new DeleteDirectory();
         dd.deleteDirectory(fl);
      }
   }

   public void deleteDirectory(File file) throws IOException
   {
      if(file.isDirectory())
      {
         if(file.list().length == 0)
         { 
            deleteEmptyDirectory(file); // here if directory is empty delete we are deleting
         }
         else
         {
            File fe[] = file.listFiles();
            for(File deleteFile : fe)
            {
               deleteDirectory(deleteFile); // recursive call
            }
            if(file.list().length == 0)
            {
               deleteEmptyDirectory(file);
            }
         }
      }
      else
      {
         file.delete();
         System.out.println("File deleted : " + file.getAbsolutePath());
      }
   }

   private void deleteEmptyDirectory(File fi)
   {
      fi.delete();
      System.out.println("Directory deleted : " + fi.getAbsolutePath());
   }
}

Weitere Informationen finden Sie unter Ressourcen

Verzeichnis löschen


0

rm -rfwar viel performanter als FileUtils.deleteDirectory.

Nach ausgiebigem Benchmarking stellten wir fest, dass die Verwendung rm -rfum ein Vielfaches schneller war als die Verwendung FileUtils.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.deleteDirectoryund nur 1 Minute dauern würde rm -rf.

Hier ist unsere grobe Java-Implementierung, um dies zu tun:

// Delete directory given and all subdirectories and files (i.e. recursively).
//
static public boolean deleteDirectory( File file ) throws IOException, InterruptedException {

    if ( file.exists() ) {

        String deleteCommand = "rm -rf " + file.getAbsolutePath();
        Runtime runtime = Runtime.getRuntime();

        Process process = runtime.exec( deleteCommand );
        process.waitFor();

        return true;
    }

    return false;

}

Es lohnt sich zu versuchen, wenn Sie mit großen oder komplexen Verzeichnissen arbeiten.


Dies funktioniert plattformübergreifend?
OneCricketeer

@ Cricket_007 Welche Plattformen?
Joshua Pinter

Windows? OpenWrt? BSD?
OneCricketeer

1
@ Cricket_007 Auf keinen Fall Windows. Dies wurde getestet und unter Android und MacOS verwendet.
Joshua Pinter

0

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.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.