it-swarm.com.de

Löschen Sie Verzeichnisse rekursiv in Java

Gibt es eine Möglichkeit, ganze Verzeichnisse in Java rekursiv zu löschen?

Im Normalfall kann ein leeres Verzeichnis gelöscht werden. Wenn es jedoch darum geht, ganze Verzeichnisse mit Inhalten zu löschen, ist das nicht mehr so ​​einfach.

Wie löscht man ganze Verzeichnisse mit Inhalten in Java?

364
paweloque

Sie sollten Apache's commons-io auschecken. Es hat eine FileUtils Klasse, die macht was Sie wollen.

FileUtils.deleteDirectory(new File("directory"));
448
Steve K

Mit Java 7 können wir endlich dies mit zuverlässiger Symlink-Erkennung (Apaches Commons-io sehe ich nicht als Zuverlässige Erkennung von Symlinks zu diesem Zeitpunkt, da mit mklink erstellte Links unter Windows nicht verarbeitet werden.)

Der Geschichte halber 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);
}
189
erickson

In Java 7+ können Sie Files class 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;
   }
});
141

Java 7 fügte Unterstützung für Laufverzeichnisse mit Symlink-Behandlung hinzu:

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 ungeprüften 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 ist von Apache Commons Lang . Prozesse sind privat, aber ihr Verhalten sollte offensichtlich sein.)

66
Trevor Robinson

One-Liner-Lösung (Java8) um alle Dateien und Verzeichnisse einschließlich des Startverzeichnisses rekursiv zu löschen:

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, sonst kann File :: delete möglicherweise nicht leeres Verzeichnis nicht löschen. Wenn Sie also Verzeichnisse behalten und nur Dateien löschen möchten, entfernen Sie einfach den Komparator in sortiert () oder Sortierung vollständig entfernen und Dateifilter hinzufügen:

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

Ich habe gerade gesehen, dass meine Lösung mehr oder weniger der von Erickson entspricht und nur als statische Methode verpackt ist. 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();
    }
}
32
Paulitex

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();
    }
}
19
trianam

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

Von Guave 1 :

Veraltet. Diese Methode leidet unter einer schlechten Symlink-Erkennung und schlechten Rennbedingungen. Diese Funktionalität kann nur dann in geeigneter Weise unterstützt werden, wenn ein Betriebssystembefehl wie rm -rf oder del /s. Diese Methode soll in Guava Release 11.0 aus Guava entfernt werden.

Daher gibt es in Guave 11 keine solche Methode.

15
Andrew McKinlay

Wenn Sie Spring haben, können Sie FileSystemUtils.deleteRecursively verwenden:

import org.springframework.util.FileSystemUtils;

boolean success = FileSystemUtils.deleteRecursively(new File("directory"));
14
Ben Hutchison
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 mit dem IOException umgehen wollen:

Files.walk(directoryToDelete).
    sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
    forEach(p -> {
        try { Files.delete(p); }
        catch(IOException e) { /* ... */ }
      });
12
user3669782
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();
}
11
AdamOutler
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();
    }
}
8
vladicho

Zwei Möglichkeiten, mit Symlinks und dem obigen Code einen Fehler zu machen ... und die Lösung nicht zu kennen.

Weg Nr. 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, wenn die Datei nicht gefunden wird. Nicht sicher, was die anderen Beispiele hier tun. Der Linux-Befehl rm löscht einfach die Verknüpfung und rm -r im Verzeichnis ebenfalls.

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

Weg Nr. 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 Beispielcode aus, den die Personen gepostet haben. 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 dirtodelete -type f -exec rm {} \;".

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

Du könntest benutzen:

org.Apache.commons.io.FileUtils.deleteQuietly(destFile);

Löscht eine Datei und löst keine Ausnahme aus. Wenn die Datei ein Verzeichnis ist, löschen Sie sie und alle Unterverzeichnisse. Der Unterschied zwischen File.delete () und dieser Methode ist: Ein zu löschendes Verzeichnis muss nicht sein leer. 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 behandelt, mit dem Ansatz, dass eine von einer Methode ausgelöste Ausnahme immer beschreiben sollte, was diese Methode versucht hat (und was fehlgeschlagen ist):

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);
    }
}
4
AgilePro

In älteren Projekten muss ich nativen Code Java) erstellen. Ich erstelle diesen Code ähnlich wie Paulitex-Code.

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
Wendel

Hier ist eine Bare-Bones-Hauptmethode, die ein Befehlszeilenargument akzeptiert. Möglicherweise müssen Sie Ihre eigene Fehlerprüfung anhängen oder sie an Ihre Bedürfnisse 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!

2
glue

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
Pranav V R

Möglicherweise besteht eine Lösung für dieses Problem darin, die Löschmethode der File-Klasse mit dem Code 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
paweloque

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();
        }

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
datahaki

Während Dateien einfach mit file.delete () gelöscht werden können, müssen die Verzeichnisse leer sein, um gelöscht zu werden. Verwenden Sie dazu einfach die Rekursion. 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
Bharat Singh

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
Shiva