Eliminar directorios de forma recursiva en Java

382

¿Hay alguna forma de eliminar directorios enteros de forma recursiva en Java?

En el caso normal, es posible eliminar un directorio vacío. Sin embargo, cuando se trata de eliminar directorios completos con contenido, ya no es tan simple.

¿Cómo se eliminan directorios completos con contenido en Java?

paweloque
fuente
44
File.delete () simplemente debería devolver falso al llamarlo con un directorio no vacío.
Ben S
Si está utilizando Java 8, consulte la respuesta de @ RoK.
Robin

Respuestas:

462

Deberías echar un vistazo a commons-io de Apache . Tiene una clase FileUtils que hará lo que quieras.

FileUtils.deleteDirectory(new File("directory"));
Steve K
fuente
3
Esta función probablemente envuelve el código que erickson proporcionó en su respuesta.
paweloque
14
Es un poco más completo. Maneja cosas como enlaces simbólicos correctamente en Linux / Unix. svn.apache.org/viewvc/commons/proper/io/trunk/src/java/org/…
Steve K
¿Por qué agregar otra dependencia cuando Java tiene una instalación lista para usar? Vea la respuesta de RoK en esta página, o stackoverflow.com/questions/35988192/…
foo
190

Con Java 7, finalmente podemos hacer esto con una detección confiable de enlaces simbólicos. (No considero que commons-io de Apache tenga una detección confiable de enlaces simbólicos en este momento, ya que no maneja enlaces en Windows creados con mklink).

Por el bien de la historia, aquí hay una respuesta anterior a Java 7, que sigue a los enlaces simbólicos.

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);
}
erickson
fuente
11
File.delete () no tiene esa funcionalidad.
Ben S
14
@Erickson: ¿No es FileNotFoundException una mala excepción para un error de eliminación? Si el archivo ya no está allí, ya debe haberse eliminado, lo que significa que, semánticamente, la eliminación no falló, no tenía nada que hacer. Y si falló por alguna otra razón, no fue porque no se encontró el archivo.
Lawrence Dol
46
Ten mucho cuidado . Esto desreferenciará los enlaces simbólicos. Si está en, por ejemplo, Linux, y tiene una carpeta foocon un enlace de foo/linktal manera link->/, ¡las llamadas delete(new File(foo)) eliminarán la mayor parte de su sistema de archivos como lo permita su usuario!
Miquel
44
@Miquel Eso no tiene sentido: ¿por qué deberíamos tener cuidado? Seguramente el objetivo del código provisto es eliminar un directorio completo, que es lo que parece hacer. No entiendo cuál es el peligro aquí.
Joehot200
12
@ Joehot200 tiene razón, llamar a eliminar en un enlace simbólico de directorio no eliminará el directorio, solo el enlace simbólico mismo. Eliminar el directorio realmente requeriría seguir el enlace simbólico explícitamente usando ReadSymbolicLink . ¡Culpa mía! Bien visto
Miquel
148

En Java 7+ puedes usar Filesclass. El código es muy simple:

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;
   }
});
Tomasz Dzięcielewski
fuente
2
¡Esta solución parece muy elegante y no contiene ninguna lógica transversal del directorio!
Zero3
1
"Para encontrar una perla sumergirse profundamente en el océano". Esta es, con mucho, la mejor solución que encontré. Tuve que sumergirme profundamente para encontrarlo. ¡Brillante!
Basil Musa
20
"El código es" NO "muy simple" simplemente para eliminar un directorio :-) Pero bueno, esa es la mejor solución en Java puro, creo.
Mat
1
Tenga en cuenta que la sobrecarga walkFileTree utilizada aquí " no sigue enlaces simbólicos ". (Javadoc: docs.oracle.com/javase/7/docs/api/java/nio/file/… )
Stephan
1
Probablemente debería llamar super.postVisitDirectory(dir, exc);a su postVisitDirectorymétodo, para hacer estallar si la caminata no pudo enumerar un directorio.
Tom Anderson
68

Solución única (Java8) para eliminar todos los archivos y directorios de forma recursiva, incluido el directorio de inicio:

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

Usamos un comparador para el orden inverso, de lo contrario File :: delete no podrá eliminar el directorio posiblemente no vacío. Entonces, si desea mantener directorios y solo eliminar archivos, simplemente elimine el comparador en sorted () o elimine la clasificación por completo y agregue el filtro de archivos:

Files.walk(Paths.get("c:/dir_to_delete/"))
                .filter(Files::isRegularFile)
                .map(Path::toFile)
                .forEach(File::delete);
RoK
fuente
1
Debe cambiar el orden en el primero a .sorted (Comparator :: reverseOrder) para eliminar todos los directorios. De lo contrario, el directorio principal se ordena antes que el secundario y, por lo tanto, no se eliminará, ya que no está vacío. ¡Gran respuesta para aquellos que usan Java 8!
Robin
1
La forma correcta es .sorted(Comparator.reverseOrder())la sugerencia Comparator::reverseOrderno no trabajar. Ver: stackoverflow.com/questions/43036611/…
user1156544
44
Robin, presta atención al signo menos en "-o1.compareTo (o2)". Es lo mismo que .sorted (Comparator.reverseOrder)
RoK
¿Files.walk es secuencial? ¿O necesita esta respuesta forEachOrdered en lugar de forEach para evitar tratar de eliminar directorios no vacíos?
Silwing
Simplemente use:, .sorted((f1, f2) -> f2.compareTo(f1))comparando f2con en f1lugar de f1con f2.
Beto Neto
67

Java 7 agregó soporte para directorios móviles con manejo de enlaces simbólicos:

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

Lo uso como alternativa de los métodos específicos de la plataforma (en este código no probado ):

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 es de Apache Commons Lang . Los procesos son privados pero su comportamiento debería ser obvio).

Trevor Robinson
fuente
Sí encuentro un problema con Files.walkFileTree: es insuficiente para implementar una versión de eliminación recursiva en la que sigues eliminando archivos hasta que te quedas sin opciones. Es adecuado para una versión a prueba de fallos, pero no siempre es lo que quiere (p. Ej., Si está limpiando archivos temporales, desea eliminar ahora, no eliminar a prueba de fallas).
Trejkaz,
No veo por qué eso es cierto. Puede manejar los errores como quiera; no es necesario que falle rápidamente. El único problema que podría prever es que podría no manejar los archivos nuevos que se crean durante el recorrido del directorio actual, pero esa es una situación única más adecuada para una solución personalizada.
Trevor Robinson
1
Si suprime el error de visitFile y llama a walkFileTree en un solo archivo que falla, no obtiene ningún error (por lo tanto, visitFile debe propagar cualquier error que ocurra). Si está eliminando un directorio y no puede eliminar un archivo, la única devolución de llamada llamada es postVisitDirectory. es decir, no visita los otros archivos en el directorio si recibe un error al visitar un archivo. Esto es lo que quiero decir. Estoy seguro de que probablemente haya alguna forma de evitar esto, pero cuando llegamos a este punto ya habíamos escrito más código que una rutina de eliminación recursiva tradicional, por lo que decidimos no usarlo.
Trejkaz
Gracias por su primer código, fue útil para mí, pero tuve que cambiarlo, porque no completó un simple deltree: tuve que ignorar la excepción en "postVisitDirectory" y regresar CONTINUAR independientemente de que el siguiente árbol simple no pudiera ser completamente ser eliminado: Un directorio dentro del cual había otro directorio dentro del cual había un archivo. Todo lo cual es tan simple / normal como se pone, en Windows.
Dreamspace President
Todo comenzó desde una java.nio.file.DirectoryNotEmptyException que obtuve. Descubrí el caso donde se utiliza visitFileFailed. Si la estructura de su directorio tiene un enlace de tipo de unión en Windows. Esto puede causar 2 problemas: *) Files.walkFileTree sigue el enlace en la unión y elimina todo lo que hay allí. *) Si el directorio de destino de la unión ya está eliminado, el análisis del enlace por Files.walkFileTree falla con NoSuchFileException, que se encuentra en visitFileFailed.
Andres Luuk
34

Acabo de ver que mi solución es más o menos la misma que la de Erickson, solo empaquetada como un método estático. Deje esto en algún lado, es mucho más liviano que instalar todos los Apache Commons para algo que (como puede ver) es bastante simple.

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

Una solución con una pila y sin métodos recursivos:

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();
    }
}
trianam
fuente
2
+1 por usar una pila. Esto funcionará con directorios que contienen niveles profundos de subdirectorios anidados, mientras que los otros enfoques basados ​​en la pila fallarán.
Nathan Osman
44
Al ver que generalmente no tiene problemas al anidar un par de cientos de llamadas a métodos, creo que es probable que se encuentre con restricciones del sistema de archivos mucho antes.
Bombe
2
Tenga cuidado con los list*métodos para la clase java.io.File. De los Javadocs: "Devuelve nulo si este nombre de ruta abstracto no denota un directorio, o si ocurre un error de E / S". Por lo tanto: if (currList.length > 0) {se convierte enif (null != currList && currList.length > 0) {
kevinarpe
1
Yo uso un ArrayDeque en lugar de un Stack que es un poco más rápido. (sin sincronizar)
Wytze
15

Si tiene Spring, puede usar FileSystemUtils.deleteRecursively :

import org.springframework.util.FileSystemUtils;

boolean success = FileSystemUtils.deleteRecursively(new File("directory"));
Ben Hutchison
fuente
15

La guayaba había Files.deleteRecursively(File)apoyado hasta la guayaba 9 .

De guayaba 10 :

Obsoleto. Este método adolece de una pobre detección de enlaces simbólicos y condiciones de carrera. Esta funcionalidad solo se puede admitir adecuadamente mediante el uso de un comando del sistema operativo como rm -rfo del /s. Este método está programado para ser eliminado de Guava en Guava versión 11.0.

Por lo tanto, no existe tal método en Guava 11 .

Andrew McKinlay
fuente
66
Demasiado. El bombardeo parece un poco tosco y no portátil. Si la versión de Apache commons funciona correctamente, entonces presumiblemente no es imposible de implementar.
Andrew McKinlay
66
@andrew La implementación de Apache Commons debería tener problemas similares a los que hacen que Guava elimine su implementación, consulte code.google.com/p/guava-libraries/issues/detail?id=365
orip
La versión de apache commons detecta enlaces simbólicos y simplemente no atraviesa los elementos secundarios del archivo.
Ajax
55
Guava 21.0 agregó esto como MoreFiles.deleteRecursively () .
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);
}

O si quieres manejar el IOException:

Files.walk(directoryToDelete).
    sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
    forEach(p -> {
        try { Files.delete(p); }
        catch(IOException e) { /* ... */ }
      });
usuario3669782
fuente
2
Esto me ayudó a encontrar una versión Scala:Files.walk(path).iterator().toSeq.reverse.foreach(Files.delete)
James Ward,
¿Es realmente necesaria la clasificación? El walkmétodo ya garantiza un recorrido transversal en profundidad.
VGR
El comparador podría reciclarse, por Collections.reverseOrder()lo que su código supondría que for (Path p : Files.walk(directoryToDelete).sorted(reverseOrder()).toArray(Path[]::new))se ha importado estáticamente.
namero999
@ namero999 ¿Quieres decir Comparator.reverseOrder? Files.walk(dir) .sorted(Comparator.reverseOrder()) .toArray(Path[]::new))
Jeff
@Jeff bastante seguro de que tienes razón, la mayoría fue de memoria allí :)
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();
}
AdamOutler
fuente
55
Versión mejorada con valor de retorno booleano y sin duplicación: 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();
    }
}
vladicho
fuente
Buen código, pero hay un error, cuando se soluciona, funciona. La línea f.delete()debajo deleteDirectory(f)arrojará NoSuchFileException porque deleteDirectory(f)ya elimina ese archivo. Cada directorio se convertirá en una ruta cuando sea pasado deleteDirectory(f)y eliminado por path.delete(). Por lo tanto, no necesitamos f.delete()en la if f.isDerectorysección. Entonces, simplemente elimine f.delete();en deleteDirectory (f) y funcionará.
Trieu Nguyen
5

Dos formas de fallar con los enlaces simbólicos y el código anterior ... y no conozco la solución.

Camino # 1

Ejecute esto para crear una prueba:

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

Aquí puede ver su archivo de prueba y el directorio de prueba:

$ ls testfile dirtodelete
testfile

dirtodelete:
linktodelete

Luego ejecute su commons-io deleteDirectory (). Se bloquea al decir que no se encuentra el archivo. No estoy seguro de lo que hacen los otros ejemplos aquí. El comando rm de Linux simplemente eliminaría el enlace, y rm -r en el directorio también lo haría.

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

Camino # 2

Ejecute esto para crear una prueba:

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

Aquí puede ver su archivo de prueba y el directorio de prueba:

$ ls dirtodelete testdir
dirtodelete:
dirlinktodelete

testdir:
testfile

Luego ejecute su commons-io deleteDirectory () o el código de ejemplo que publicaron las personas. No solo elimina el directorio, sino también el archivo de prueba que está fuera del directorio que se está eliminando. (Elimina la referencia del directorio implícitamente y elimina los contenidos). rm -r eliminaría solo el enlace. Debe usar algo como esto, elimine los archivos desreferenciados: "find -L dirtodelete -type f -exec rm {} \;".

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

Podrías usar:

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

Elimina un archivo, nunca arroja una excepción. Si el archivo es un directorio, elimínelo y todos los subdirectorios. La diferencia entre File.delete () y este método es: Un directorio a eliminar no tiene que estar vacío. No se producen excepciones cuando un archivo o directorio no se puede eliminar.

Jan-Terje Sørensen
fuente
4

Una solución óptima que maneja la excepción de manera consistente con el enfoque de que una excepción lanzada desde un método siempre debe describir lo que ese método estaba intentando (y no pudo) hacer:

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

En proyectos heredados, necesito crear código Java nativo. Creo este código similar al código Paulitex. Mira eso:

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

Y la prueba de la unidad:

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

}
Wendel
fuente
3

El siguiente código borra recursivamente todo el contenido de una carpeta determinada.

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

Aquí hay un método principal básico que acepta un argumento de línea de comando, es posible que deba agregar su propia comprobación de errores o moldearlo como mejor le parezca.

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

¡Espero que eso ayude!

pegamento
fuente
1

Quizás una solución para este problema podría ser volver a implementar el método de eliminación de la clase File usando el código de la respuesta de erickson:

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();
    }
  }
}
paweloque
fuente
1
Creo que está implementado ya que es para imitar el comportamiento de la mayoría de las utilidades de shell de comandos como "rm", "rmdir" y "del". De las dos alternativas, la implementación actual definitivamente minimiza el potencial general de sorpresa (y enojo). No va a cambiar
erickson
44
En general, los únicos paquetes Java JRE que veo extendidos son de Swing. Por lo general, ampliar otras clases como java.io.File es una mala idea, ya que tiene la posibilidad de hacer que las cosas actúen de manera inesperada.
Eddie
1

Sin Commons IO y <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();
        }
Alexander Sidikov Pfeif
fuente
0

Si bien los archivos se pueden eliminar fácilmente usando file.delete (), los directorios deben estar vacíos para eliminarse. Use la recursividad para hacer esto fácilmente. Por ejemplo:

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();
                        }
                    }
                }
            }
        }
    }
Bharat Singh
fuente
0

Codifiqué esta rutina que tiene 3 criterios de seguridad para un uso más seguro.

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);
    }
}
datahaki
fuente
0

Bueno, supongamos un ejemplo,

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

Para obtener más información, consulte los siguientes recursos

Eliminar directorio

Shiva
fuente
0

rm -rffue mucho más eficiente queFileUtils.deleteDirectory .

Después de una evaluación comparativa exhaustiva, descubrimos que usar rm -rfera varias veces más rápido que usarFileUtils.deleteDirectory .

Por supuesto, si tiene un directorio pequeño o simple, no importará, pero en nuestro caso teníamos varios gigabytes y subdirectorios profundamente anidados donde tomaría más de 10 minutos con FileUtils.deleteDirectoryy solo 1 minuto con rm -rf.

Aquí está nuestra implementación aproximada de Java para hacer eso:

// 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;

}

Vale la pena intentarlo si se trata de directorios grandes o complejos.

Joshua Pinter
fuente
Esto funciona multiplataforma?
OneCricketeer
@ cricket_007 ¿Qué plataformas?
Joshua Pinter
Windows? OpenWrt? BSD?
OneCricketeer
1
@ cricket_007 Definitivamente no Windows. Esto fue probado y utilizado en Android y macOS.
Joshua Pinter
0

La guayaba ofrece una línea:MoreFiles.deleteRecursively() .

A diferencia de muchos de los ejemplos compartidos, tiene en cuenta los enlaces simbólicos y no (por defecto) eliminará los archivos fuera de la ruta proporcionada.

dimo414
fuente