Frage

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

Im Normalfall ist es möglich, ein leeres Verzeichnis zu löschen. Allerdings, wenn es um das Löschen ganze Verzeichnisse mit Inhalten kommt, ist es nicht so einfach mehr.

Wie lösche Sie ganze Verzeichnisse mit Inhalten in Java?

War es hilfreich?

Lösung

Sie sollten überprüfen Apache commons-io . Es hat eine FileUtils Klasse, die das tun, was Sie wollen.

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

Andere Tipps

Mit Java 7, können wir endlich tun dies mit zuverlässiger Symlink-Erkennung. (Ich glaube nicht, Apache commons- io haben zuverlässig Symlink Erkennung zu diesem Zeitpunkt, da es Links auf Windows behandelt nicht mit mklink erstellt.)

Aus Gründen der Geschichte, hier ist eine Pre-Java 7 Antwort, die 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);
}

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

Java 7 Unterstützung für Verzeichnisse mit Symlink Handhabung Gehen:

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 benutze dies als Ausweich von plattformspezifischen Methoden (in diesem ungetestet 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 . Processes ist privat, aber sein Verhalten sollte klar sein.)

One-Liner-Lösung (Java8) löschen Sie alle Dateien und Verzeichnisse rekursiv einschließlich Startverzeichnis:

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 umgekehrte Reihenfolge, sonst Datei :: löschen nicht in der Lage sein, möglicherweise nicht-leeres Verzeichnis zu löschen. Also, wenn Sie Verzeichnisse halten wollen und nur Dateien löschen entfernen Sie einfach den Komparator in sortierter () oder vollständig entfernen Sortieren und Dateien Filter hinzufügen:

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

Gerade gesehen, meine Lösung ist mehr oder weniger die gleiche wie Erickson, nur als statische Methode verpackt. Schau mal diese irgendwo, es ist viel leichter als alle Apache Commons für etwas zu installieren, die (wie man sieht) ist ganz einfach.

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

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

Guava hatte Files.deleteRecursively(File) bis Guava 9 .

Von Guava 10 :

  

Veraltet. Dieses Verfahren leidet schlechte Symlink-Erkennung und Rennbedingungen. Diese Funktionalität kann durch Beschuss aus zu einem Betriebssystembefehl, wie rm -rf oder del /s nur unterstützt werden, in geeigneter Weise. Diese Methode soll von Guava in Guava Version 11.0 entfernt werden.

Daher gibt es keine solche Methode in Guava 11 .

Wenn Sie Frühling haben, können Sie FileSystemUtils.deleteRecursively :

import org.springframework.util.FileSystemUtils;

boolean success = FileSystemUtils.deleteRecursively(new File("directory"));
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 die IOException behandeln:

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

Zwei Wege mit Symlinks und dem obigen Code zu scheitern ... und wissen nicht die Lösung.

Way # 1

Führen Sie diese einen Test zu erstellen:

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

Hier sehen Sie Ihre Testdatei und Testverzeichnis:

$ ls testfile dirtodelete
testfile

dirtodelete:
linktodelete

Dann führen Sie Ihre commons-io deleteDirectory (). Stürzt, dass die Datei nicht gefunden wird. Nicht sicher, was die anderen Beispiele hier tun. Die Linux-Befehl rm würde einfach löschen Sie den Link, und rm -r auf das Verzeichnis würde auch.

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

Way # 2

Führen Sie diese einen Test zu erstellen:

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

Hier sehen Sie Ihre Testdatei und Testverzeichnis:

$ ls dirtodelete testdir
dirtodelete:
dirlinktodelete

testdir:
testfile

Dann wird Ihr commons-io deleteDirectory () oder die Beispiel-Code Menschen geschrieben laufen. Es löscht nicht nur das Verzeichnis, aber Ihre Testdatei, die das Verzeichnis außerhalb gelöscht werden. (Es dereferenziert das Verzeichnis implizit, und löscht den Inhalt). rm -r würde die Verbindung nur löschen. Sie müssen so etwas wie dies die dereferenzierte Dateien löschen verwenden. „Finden -L dirtodelete -type f exec rm {} \;“

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

Sie können verwendet werden:

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

Löscht eine Datei, nie eine Ausnahme zu werfen. Wenn Datei ein Verzeichnis ist, löschen und alle Unterverzeichnisse. Der Unterschied zwischen File.delete () und dieser Methode sind: Ein Verzeichnis gelöscht werden muss nicht leer sein. Es sind keine Ausnahmen ausgelöst, wenn eine Datei oder ein Verzeichnis kann nicht gelöscht werden.

Eine optimale Lösung, die Ausnahme im Einklang mit dem Ansatz behandelt, dass eine Ausnahme von einer Methode geworfen sollte immer beschreiben, was das Verfahren versucht (und nicht) zu tun:

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

In Legacy-Projekten, ich brauche native Java-Code zu erstellen. Ich schaffe diesen Code ähnlich wie Paulitex Code. Sehen Sie, dass:

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 das Gerät zu testen:

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

}

Hier ist eine nackte Knochen Hauptmethode, die eine Kommandozeilen-Argument akzeptiert, können Sie Ihre eigene Fehlerprüfung oder Form es, wie Sie sehen, passen anhängen müssen.

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!

Im Folgenden Code rekursiv alle Inhalte in einem bestimmten Ordner löschen.

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

Vielleicht könnte eine Lösung für dieses Problem sein, die Löschmethode der File-Klasse von Erickson Antwort mit dem Code neu 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();
    }
  }
}

Ohne Commons IO und

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

Während Dateien einfach gelöscht werden können mit File.Delete () werden Verzeichnisse erforderlich leer sein gelöscht werden. Verwenden Sie Rekursion 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();
                        }
                    }
                }
            }
        }
    }

i codiert diese Routine, die drei Sicherheitskriterien für eine sicherere Nutzung 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);
    }
}

Nun, lassen Sie uns ein Beispiel annehmen,

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 unter Ressourcen beziehen

Verzeichnis löschen

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top