¿Cómo eliminar toda una carpeta y contenido?

187

Quiero que los usuarios de mi aplicación puedan eliminar la carpeta DCIM (que se encuentra en la tarjeta SD y contiene subcarpetas).

¿Es esto posible? De ser así, ¿cómo?

Principiante
fuente
1
aparte del enfoque recursivo de eliminación ascendente?
Sarwar Erfan
Si tiene un directorio muy grande o complejo, debe usarlo en rm -rf directorylugar de FileUtils.deleteDirectory. Después de la evaluación comparativa, descubrimos que era varias veces más rápido. Echa un vistazo a una implementación de muestra aquí: stackoverflow.com/a/58421350/293280
Joshua Pinter el

Respuestas:

301

Permítame decirle lo primero que no puede eliminar la carpeta DCIM porque es una carpeta del sistema. A medida que lo elimine manualmente en el teléfono, eliminará el contenido de esa carpeta, pero no la carpeta DCIM. Puede eliminar su contenido utilizando el siguiente método:

Actualizado según los comentarios

File dir = new File(Environment.getExternalStorageDirectory()+"Dir_name_here"); 
if (dir.isDirectory()) 
{
    String[] children = dir.list();
    for (int i = 0; i < children.length; i++)
    {
       new File(dir, children[i]).delete();
    }
}
chikka.anddev
fuente
3
erm, ¿cómo declaro qué es dir?
Principiante
Básicamente, estoy tratando de eliminar todas las fotos, así que no importa, DCIM no se eliminará mientras las fotos lo estén ... así que incluso eliminar 100MEDIA la carpeta dentro de esto haría el trabajo
Principiante
1
debe declarar el directorio utilizando la ruta de la carpeta dicm: use el archivo r = archivo (ruta);
chikka.anddev
3
dir de archivo usado = nuevo archivo (Environment.getExternalStorageDirectory () + "/ DCIM / 100MEDIA");
Principiante del
1
@chiragshah Después de eliminar una carpeta y volver a crear la carpeta, lo que resulta en la creación de un archivo desconocido con el mismo nombre de la carpeta mencionada. Y si estoy tratando de acceder a ese archivo, arroja una excepción como Recurso o dispositivo ocupado . archivo donde encontré MD5 Signature: Operation Failure
sha
529

Puede eliminar archivos y carpetas de forma recursiva de esta manera:

void deleteRecursive(File fileOrDirectory) {
    if (fileOrDirectory.isDirectory())
        for (File child : fileOrDirectory.listFiles())
            deleteRecursive(child);

    fileOrDirectory.delete();
}
teedyay
fuente
21
No he realizado pruebas de eficiencia, pero creo que la mía es más robusta. chirag's funcionará para el caso específico de la carpeta DCIM, donde las carpetas dentro de DCIM deben contener solo archivos (es decir, las carpetas dentro de DCIM normalmente no contienen ninguna subcarpeta). Mi versión eliminará las carpetas que están anidadas a cualquier profundidad. Existe la posibilidad de que el usuario haya modificado el contenido de su tarjeta SD para que DCIM contenga carpetas anidadas más profundamente (por ejemplo DCIM\foo\bar\pic.jpg), en cuyo caso el código de chirag fallará.
teedyay
2
Una pregunta que me hizo un colega: ¿Qué sucede si una carpeta tiene un enlace simbólico en sí mismo y usted ejecuta esta porción de código?
p4u144
1
@ p4u144 ¡Dale a tu colega cinco por ser un genio! ¡Bien descrito! Para ser honesto, no sé si este código respetaría o no los enlaces simbólicos, pero si lo hace, tendrá un bucle infinito. ¿Te apetece probarlo?
teedyay
8
@ p4u144 No se preocupe por los enlaces simbólicos. "Con enlaces simbólicos, el enlace se elimina y no el objetivo del enlace". de docs.oracle.com/javase/tutorial/essential/io/delete.html
corbin
3
Hay un posible NPE aquí: fileOrDirectory.listFiles()puede regresar nullsi hay un error de E / S al leer los archivos. Esto se indica claramente en la documentación: developer.android.com/reference/java/io/File.html#listFiles ()
Brian Yencho
67

Podemos usar los argumentos de la línea de comandos para eliminar una carpeta completa y su contenido.

public static void deleteFiles(String path) {

    File file = new File(path);

    if (file.exists()) {
        String deleteCmd = "rm -r " + path;
        Runtime runtime = Runtime.getRuntime();
        try {
            runtime.exec(deleteCmd);
        } catch (IOException e) { }
    }
}

Ejemplo de uso del código anterior:

deleteFiles("/sdcard/uploads/");
xinaxino
fuente
2
parece bueno, ¿sabes si esto es síncrono o asíncrono? La documentación no dice: developer.android.com/reference/java/lang/…
Someone Somewhere
2
Mala idea. ¿Por qué hacerlo en la cáscara?
noamtm
1
@SomeoneSomewhere async docs.oracle.com/javase/7/docs/api/java/lang/…
sudocoder
34

En Kotlin puedes usar la deleteRecursively()extensión del kotlin.iopaquete

val someDir = File("/path/to/dir")
someDir.deleteRecursively()
Dima Rostopira
fuente
2
En Java puede usar FilesKt.deleteRecursively(new File("/path/to/dir"));si está usando kotlin-stdlib
Joonsoo
Este comando eliminará el directorio "/ dir" con el contenido dentro o solo el contenido dentro del directorio "/ dir" y el directorio permanecerá allí.
Bhimbim
1
@Bhimbim déjame documentos de Google para ti "Elimina este archivo con todos sus elementos secundarios". Por lo tanto, se eliminará el directorio y los contenidos
Dima Rostopira
Gracias @DimaRostopira!
Bhimbim
Kotlin al rescate!
Tobi Oyelekan
15

utilice el siguiente método para eliminar todo el directorio principal que contiene archivos y su subdirectorio. Después de llamar a este método una vez más, llame al directorio delete () de su directorio principal.

// For to Delete the directory inside list of files and inner Directory
public static boolean deleteDir(File dir) {
    if (dir.isDirectory()) {
        String[] children = dir.list();
        for (int i=0; i<children.length; i++) {
            boolean success = deleteDir(new File(dir, children[i]));
            if (!success) {
                return false;
            }
        }
    }

    // The directory is now empty so delete it
    return dir.delete();
}
Androide
fuente
De todas las respuestas, esta es la ÚNICA respuesta real que elimina el directorio también después de eliminar los archivos en él.
zeeshan
Archivo de archivo = Archivo nuevo (Environment.getExternalStorageDirectory () + separador + "nombre_carpeta" + separador); deleteDir (archivo); Sí, esto funciona. Gracias :)
ashishdhiman2007 05 de
14

Su enfoque es decente para una carpeta que solo contiene archivos, pero si está buscando un escenario que también contenga subcarpetas, entonces se necesita recurrencia

También debe capturar el valor de retorno de la devolución para asegurarse de que tiene permiso para eliminar el archivo

e incluir

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

en tu manifiesto

void DeleteRecursive(File dir)
{
    Log.d("DeleteRecursive", "DELETEPREVIOUS TOP" + dir.getPath());
    if (dir.isDirectory())
    {
        String[] children = dir.list();
        for (int i = 0; i < children.length; i++)
        {
            File temp = new File(dir, children[i]);
            if (temp.isDirectory())
            {
                Log.d("DeleteRecursive", "Recursive Call" + temp.getPath());
                DeleteRecursive(temp);
            }
            else
            {
                Log.d("DeleteRecursive", "Delete File" + temp.getPath());
                boolean b = temp.delete();
                if (b == false)
                {
                    Log.d("DeleteRecursive", "DELETE FAIL");
                }
            }
        }

    }
    dir.delete();
}
GregM
fuente
55
Esto podría ser más fácil si lo usa para (File currentFile: file.listFiles ()) {
Thorben
8

Hay muchas respuestas, pero decidí agregar las mías, porque es un poco diferente. Se basa en OOP;)

Creé la clase DirectoryCleaner , que me ayuda cada vez que necesito limpiar algún directorio.

public class DirectoryCleaner {
    private final File mFile;

    public DirectoryCleaner(File file) {
        mFile = file;
    }

    public void clean() {
        if (null == mFile || !mFile.exists() || !mFile.isDirectory()) return;
        for (File file : mFile.listFiles()) {
            delete(file);
        }
    }

    private void delete(File file) {
        if (file.isDirectory()) {
            for (File child : file.listFiles()) {
                delete(child);
            }
        }
        file.delete();

    }
}

Se puede utilizar para resolver este problema de la siguiente manera:

File dir = new File(Environment.getExternalStorageDirectory(), "your_directory_name");
new DirectoryCleaner(dir).clean();
dir.delete();
gio
fuente
7

Si no necesita eliminar cosas de forma recursiva, puede intentar algo como esto:

File file = new File(context.getExternalFilesDir(null), "");
    if (file != null && file.isDirectory()) {
        File[] files = file.listFiles();
        if(files != null) {
            for(File f : files) {   
                f.delete();
            }
        }
    }
Marty
fuente
6

No puede eliminar el directorio si tiene subdirectorios o archivos en Java. Pruebe esta solución simple de dos líneas. Esto eliminará el directorio y los concursos dentro del directorio.

File dirName = new File("directory path");
FileUtils.deleteDirectory(dirName);

Agregue esta línea en el archivo gradle y sincronice el proyecto

compile 'org.apache.commons:commons-io:1.3.2'  
Vigneswaran A
fuente
Como 2 liner, es simple. Pero instalar una biblioteca completa para utilizar solo uno de sus métodos parece ineficiente. Use esto en su lugar
Kathir el
La punta de inserción de gradle me salvó la vida.
Dracarys
5
public static void deleteDirectory( File dir )
{

    if ( dir.isDirectory() )
    {
        String [] children = dir.list();
        for ( int i = 0 ; i < children.length ; i ++ )
        {
         File child =    new File( dir , children[i] );
         if(child.isDirectory()){
             deleteDirectory( child );
             child.delete();
         }else{
             child.delete();

         }
        }
        dir.delete();
    }
}
Verma profundo
fuente
4

De acuerdo con la documentación :

Si este nombre de ruta abstracto no denota un directorio, entonces este método devuelve nulo.

Por lo tanto, debe verificar si listFileses nully solo continuar si no es

boolean deleteDirectory(File path) {
    if(path.exists()) {
        File[] files = path.listFiles();
        if (files == null) {
            return false;
        }
        for (File file : files) {
            if (file.isDirectory()) {
                deleteDirectory(file);
            } else {
                boolean wasSuccessful = file.delete();
                if (wasSuccessful) {
                    Log.i("Deleted ", "successfully");
                }
            }
        }
    }
    return(path.delete());
}
MEDIA PENSIÓN.
fuente
1
Esta debería ser la respuesta aceptada. ¡Funciona de maravilla!
MSeiz5
3

Esto es lo que hago ... (breve y probado)

    ...
    deleteDir(new File(dir_to_be_deleted));
    ...

    // delete directory and contents
    void deleteDir(File file) { 
        if (file.isDirectory())
            for (String child : file.list())
                deleteDir(new File(file, child));
        file.delete();  // delete child file or empty directory
    }
SoloPilot
fuente
3
private static void deleteRecursive(File dir)
{
    //Log.d("DeleteRecursive", "DELETEPREVIOUS TOP" + dir.getPath());
    if (dir.isDirectory())
    {
        String[] children = dir.list();
        for (int i = 0; i < children.length; i++)
        {
            File temp = new File(dir, children[i]);
            deleteRecursive(temp);
        }

    }

    if (dir.delete() == false)
    {
        Log.d("DeleteRecursive", "DELETE FAIL");
    }
}
JasonCheung
fuente
2

Manera simple de eliminar todos los archivos del directorio:

Es una función genérica para eliminar todas las imágenes del directorio llamando solo

deleteAllImageFile (contexto);

public static void deleteAllFile(Context context) {
File directory = context.getExternalFilesDir(null);
        if (directory.isDirectory()) {
            for (String fileName: file.list()) {
                new File(file,fileName).delete();
            }
        }    
    } 
Sarage Chorage
fuente
2

El código más seguro que conozco:

private boolean recursiveRemove(File file) {
    if(file == null  || !file.exists()) {
        return false;
    }

    if(file.isDirectory()) {
        File[] list = file.listFiles();

        if(list != null) {

            for(File item : list) {
                recursiveRemove(item);
            }

        }
    }

    if(file.exists()) {
        file.delete();
    }

    return !file.exists();
}

Comprueba que el archivo existe, maneja nulos, comprueba que el directorio se haya eliminado realmente

Gary Davies
fuente
2

Versión corta de koltin

fun File.deleteDirectory(): Boolean {
    return if (exists()) {
        listFiles()?.forEach {
            if (it.isDirectory) {
                it.deleteDirectory()
            } else {
                it.delete()
            }
        }
        delete()
    } else false
}
Vlad
fuente
1

Aquí hay una implementación no recursiva, solo por diversión:

/**
 * Deletes the given folder and all its files / subfolders.
 * Is not implemented in a recursive way. The "Recursively" in the name stems from the filesystem command
 * @param root The folder to delete recursively
 */
public static void deleteRecursively(final File root) {
    LinkedList<File> deletionQueue = new LinkedList<>();
    deletionQueue.add(root);

    while(!deletionQueue.isEmpty()) {
        final File toDelete = deletionQueue.removeFirst();
        final File[] children = toDelete.listFiles();
        if(children == null || children.length == 0) {
            // This is either a file or an empty directory -> deletion possible
            toDelete.delete();
        } else {
            // Add the children before the folder because they have to be deleted first
            deletionQueue.addAll(Arrays.asList(children));
            // Add the folder again because we can't delete it yet.
            deletionQueue.addLast(toDelete);
        }
    }
}
PhilLab
fuente
1

Esto (intenta eliminar todos los subarchivos y subdirectorios, incluido el directorio suministrado) :

  1. Si File, eliminar
  2. Si Empty Directory, eliminar
  3. si Not Empty Directory, llame a eliminar nuevamente con el subdirectorio, repita 1 a 3

ejemplo:

File externalDir = Environment.getExternalStorageDirectory()
Utils.deleteAll(externalDir); //BE CAREFUL.. Will try and delete ALL external storage files and directories

Para obtener acceso al Directorio de almacenamiento externo, necesita los siguientes permisos:

(Usar ContextCompat.checkSelfPermissiony ActivityCompat.requestPermissions)

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Método recursivo:

public static boolean deleteAll(File file) {
    if (file == null || !file.exists()) return false;

    boolean success = true;
    if (file.isDirectory()) {
        File[] files = file.listFiles();
        if (files != null && files.length > 0) {
            for (File f : files) {
                if (f.isDirectory()) {
                    success &= deleteAll(f);
                }
                if (!f.delete()) {
                    Log.w("deleteAll", "Failed to delete " + f);
                    success = false;
                }
            }
        } else {
            if (!file.delete()) {
                Log.w("deleteAll", "Failed to delete " + file);
                success = false;
            }
        }
    } else {
        if (!file.delete()) {
            Log.w("deleteAll", "Failed to delete " + file);
            success = false;
        }
    }
    return success;
}
Pierre
fuente
0

He puesto este, aunque sus pasos eliminan una carpeta con cualquier estructura de directorio.

public int removeDirectory(final File folder) {

    if(folder.isDirectory() == true) {
        File[] folderContents = folder.listFiles();
        int deletedFiles = 0;

        if(folderContents.length == 0) {
            if(folder.delete()) {
                deletedFiles++;
                return deletedFiles;
            }
        }
        else if(folderContents.length > 0) {

            do {

                File lastFolder = folder;
                File[] lastFolderContents = lastFolder.listFiles();

                //This while loop finds the deepest path that does not contain any other folders
                do {

                    for(File file : lastFolderContents) {

                        if(file.isDirectory()) {
                            lastFolder = file;
                            lastFolderContents = file.listFiles();
                            break;
                        }
                        else {

                            if(file.delete()) {
                                deletedFiles++;
                            }
                            else {
                                break;
                            }

                        }//End if(file.isDirectory())

                    }//End for(File file : folderContents)

                } while(lastFolder.delete() == false);

                deletedFiles++;
                if(folder.exists() == false) {return deletedFiles;}

            } while(folder.exists());
        }
    }
    else {
        return -1;
    }

    return 0;

}

Espero que esto ayude.

usuario2288580
fuente
0
//To delete all the files of a specific folder & subfolder
public static void deleteFiles(File directory, Context c) {
    try {
        for (File file : directory.listFiles()) {
            if (file.isFile()) {
                final ContentResolver contentResolver = c.getContentResolver();
                String canonicalPath;
                try {
                    canonicalPath = file.getCanonicalPath();
                } catch (IOException e) {
                    canonicalPath = file.getAbsolutePath();
                }
                final Uri uri = MediaStore.Files.getContentUri("external");
                final int result = contentResolver.delete(uri,
                        MediaStore.Files.FileColumns.DATA + "=?", new String[]{canonicalPath});
                if (result == 0) {
                    final String absolutePath = file.getAbsolutePath();
                    if (!absolutePath.equals(canonicalPath)) {
                        contentResolver.delete(uri,
                                MediaStore.Files.FileColumns.DATA + "=?", new String[]{absolutePath});
                    }
                }
                if (file.exists()) {
                    file.delete();
                    if (file.exists()) {
                        try {
                            file.getCanonicalFile().delete();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        if (file.exists()) {
                            c.deleteFile(file.getName());
                        }
                    }
                }
            } else
                deleteFiles(file, c);
        }
    } catch (Exception e) {
    }
}

Aquí está su solución, también actualizará la galería.

Bilal Mustafa
fuente
0

Otra forma (moderna) de resolverlo.

public class FileUtils {
    public static void delete(File fileOrDirectory) {
        if(fileOrDirectory != null && fileOrDirectory.exists()) {
            if(fileOrDirectory.isDirectory() && fileOrDirectory.listFiles() != null) {      
                Arrays.stream(fileOrDirectory.listFiles())
                      .forEach(FileUtils::delete);
            }
            fileOrDirectory.delete();
        }
    }
}

En Android desde API 26

public class FileUtils {

    public static void delete(File fileOrDirectory)  {
        if(fileOrDirectory != null) {
            delete(fileOrDirectory.toPath());
        }
    }

    public static void delete(Path path)  {
        try {
            if(Files.exists(path)) {
                Files.walk(path)
                        .sorted(Comparator.reverseOrder())
                        .map(Path::toFile)
//                      .peek(System.out::println)
                        .forEach(File::delete);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
Ch4rl3x
fuente
0

Estoy usando esta función recursiva para hacer el trabajo:

public static void deleteDirAndContents(@NonNull File mFile){
    if (mFile.isDirectory() && mFile.listFiles() != null && mFile.listFiles().length > 0x0) {
        for (File file : mFile.listFiles()) {
            deleteDirAndContents(file);
        }
    } else {
        mFile.delete();
    }
}

La función comprueba si es un directorio o un archivo.

Si es un directorio, verifica si tiene archivos secundarios, si tiene archivos secundarios se llamará a sí misma nuevamente pasando a los hijos y repitiendo.

Si es un archivo, elimínelo.

(No use esta función para borrar el caché de la aplicación pasando el directorio de caché porque también eliminará el directorio de caché, por lo que la aplicación se bloqueará ... Si desea borrar el caché, use esta función que no borrará el dir pasas a ella:

public static void deleteDirContents(@NonNull File mFile){
        if (mFile.isDirectory() && mFile.listFiles() != null && mFile.listFiles().length > 0x0) {
            for (File file : mFile.listFiles()) {
                deleteDirAndContents(file);
            }
        }
    }

o puede verificar si es el directorio de caché usando:

if (!mFile.getAbsolutePath().equals(context.getCacheDir().getAbsolutePath())) {
    mFile.delete();
}

Código de ejemplo para borrar el caché de la aplicación:

public static void clearAppCache(Context context){
        try {
            File cache = context.getCacheDir();
            FilesUtils.deleteDirContents(cache);
        } catch (Exception e){
            MyLogger.onException(TAG, e);
        }
    }

Adiós, que tengas un buen día y codificación: D

Z3R0
fuente