Come eliminare un'intera cartella e contenuto?


187

Voglio che gli utenti della mia applicazione siano in grado di eliminare la cartella DCIM (che si trova sulla scheda SD e contiene sottocartelle).

È possibile, se sì come?


1
diverso dall'approccio di eliminazione dal basso ricorsivo?
Sarwar Erfan,

Se hai una directory molto grande o complessa, dovresti usare rm -rf directoryinvece di FileUtils.deleteDirectory. Dopo il benchmarking abbiamo scoperto che era più volte più veloce. Dai un'occhiata a un'implementazione di esempio qui: stackoverflow.com/a/58421350/293280
Joshua Pinter

Risposte:


301

Consentitemi di dirvi innanzitutto che non è possibile eliminare la cartella DCIM perché è una cartella di sistema. Quando lo elimini manualmente sul telefono, eliminerà il contenuto di quella cartella, ma non la cartella DCIM. Puoi eliminarne il contenuto usando il metodo seguente:

Aggiornato come da commenti

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

3
come posso dichiarare che dir è?
Principiante

sto fondamentalmente cercando di eliminare tutte le foto quindi non importa che DCIM non venga cancellato fintanto che le foto sono ... quindi anche eliminare 100MEDIA la cartella all'interno di questo farebbe il lavoro
Principiante

1
devi dichiarare la directory usando il percorso della cartella dicm: usa il file r = file (percorso);
chikka.anddev,

3
usato File dir = new File (Environment.getExternalStorageDirectory () + "/ DCIM / 100MEDIA");
Principiante

1
@chiragshah Dopo aver eliminato una cartella e ricreata la cartella con conseguente creazione di un file sconosciuto con lo stesso nome della cartella menzionata. E se sto provando ad accedere a quel file, sta generando un'eccezione come Risorsa o dispositivo occupato . Ho anche controllato le proprietà di file in cui ho trovato la firma MD5: operazione non riuscita
sha

529

Puoi eliminare ricorsivamente file e cartelle in questo modo:

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

    fileOrDirectory.delete();
}

21
Non ho fatto test per l'efficienza, ma credo che il mio sia più robusto. chirag funzionerà per il caso specifico della cartella DCIM, dove le cartelle all'interno di DCIM dovrebbero contenere solo file (cioè le cartelle all'interno di DCIM normalmente non contengono alcuna sottocartella). La mia versione eliminerà le cartelle nidificate a qualsiasi profondità. È possibile che l'utente abbia modificato il contenuto della sua scheda SD in modo che DCIM contenga cartelle nidificate più profondamente (ad es. DCIM\foo\bar\pic.jpg), Nel qual caso il codice di chirag fallirà.
teedyay,

2
Una domanda che mi ha fatto un collega: cosa succede se una cartella ha un collegamento simbolico su se stessa e si esegue questo blocco di codice?
p4u144,

1
@ p4u144 Dai al tuo collega il cinque per essere un genio! Ben individuato! Ad essere sincero, non so se questo codice rispetti o segua i collegamenti simbolici, ma se lo fa avrai un ciclo infinito. Ti va di provarlo?
oggi

8
@ p4u144 Nessuna preoccupazione per i collegamenti simbolici. "Con i collegamenti simbolici, il collegamento viene eliminato e non la destinazione del collegamento." da docs.oracle.com/javase/tutorial/essential/io/delete.html
corbin,

3
C'è un possibile NPE qui: fileOrDirectory.listFiles()può tornare in nullcaso di errore I / O durante la lettura dei file. Questo è indicato chiaramente nella documentazione: developer.android.com/reference/java/io/File.html#listFiles ()
Brian Yencho

67

Possiamo usare gli argomenti della riga di comando per eliminare un'intera cartella e il suo contenuto.

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

Esempio di utilizzo del codice sopra:

deleteFiles("/sdcard/uploads/");

2
sembra buono, sai se questo è sincrono o asincrono? La documentazione non dice: developer.android.com/reference/java/lang/…
Someone Somewhere

2
Cattiva idea. Perché farlo sul guscio?
Noamtm,


34

In Kotlin puoi usare l' deleteRecursively()estensione dal kotlin.iopacchetto

val someDir = File("/path/to/dir")
someDir.deleteRecursively()

2
In Java puoi usare FilesKt.deleteRecursively(new File("/path/to/dir"));se stai usando kotlin-stdlib
Joonsoo il

Questo comando eliminerà la directory "/ dir" con il contenuto all'interno o solo il contenuto all'interno della directory "/ dir" e la directory rimarrà lì?
Bhimbim,

1
@Bhimbim lemme google docs per te "Elimina questo file con tutti i suoi figli.". Quindi, la directory verrà eliminata così come i contenuti
Dima Rostopira,

Grazie @DimaRostopira!
Bhimbim,

kotlin in soccorso!
Tobi Oyelekan,

15

utilizzare il metodo seguente per eliminare l'intera directory principale che contiene i file e la relativa directory secondaria. Dopo aver chiamato questo metodo, chiama di nuovo la directory delete () della tua directory principale.

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

Di tutte le risposte, questa è l'UNICA vera risposta che elimina anche la directory dopo aver eliminato i file in essa contenuti.
zeeshan,

File file = new File (Environment.getExternalStorageDirectory () + separator + "nome_cartella" + separatore); deleteDir (file); Sì, funziona. Grazie :)
ashishdhiman2007,

14

Il tuo approccio è decente per una cartella che contiene solo file, ma se stai cercando uno scenario che contenga anche sottocartelle, è necessaria la ricorsione

Inoltre, è necessario acquisire il valore di ritorno del reso per assicurarsi di poter cancellare il file

e includere

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

nel tuo manifest

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

5
Questo potrebbe essere più semplice se si utilizza per (File currentFile: file.listFiles ()) {
Thorben

8

Ci sono molte risposte, ma ho deciso di aggiungere le mie, perché è leggermente diverso. È basato su OOP;)

Ho creato la classe DirectoryCleaner , che mi aiuta ogni volta che devo pulire alcune directory.

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

    }
}

Può essere usato per risolvere questo problema nel prossimo modo:

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

7

Se non hai bisogno di eliminare le cose in modo ricorsivo puoi provare qualcosa del genere:

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

6

Non è possibile eliminare la directory se contiene sottodirectory o file in Java. Prova questa soluzione semplice a due righe. Ciò eliminerà la directory e i concorsi all'interno della directory.

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

Aggiungi questa riga nel file gradle e sincronizza il progetto

compile 'org.apache.commons:commons-io:1.3.2'  

Come un liner 2, è semplice. Ma l'installazione di un'intera libreria per utilizzare solo uno dei suoi metodi sembra inefficiente. Usa questo invece
Kathir

la punta dell'inserto gradle mi ha salvato la vita.
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();
    }
}


4

Secondo la documentazione :

Se questo percorso astratto non indica una directory, questo metodo restituisce null.

Quindi dovresti controllare se lo listFilesè nulle continuare solo se non lo è

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

1
Questa dovrebbe essere la risposta accettata. Funziona come un fascino!
MSeiz5

3

Questo è quello che faccio ... (conciso e testato)

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

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

2

Modo semplice per eliminare tutti i file dalla directory:

È una funzione generica per eliminare tutte le immagini dalla directory chiamando solo

deleteAllImageFile (contesto);

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

2

Codice più sicuro che conosco:

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

Verifica l'esistenza del file, gestisce i valori null, verifica che la directory sia stata effettivamente eliminata


2

Versione corta di koltin

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

1

Ecco un'implementazione non ricorsiva, solo per divertimento:

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

1

Questo (tenta di eliminare tutti i file secondari e le directory secondarie inclusa la directory fornita) :

  1. Se File, cancella
  2. Se Empty Directory, cancella
  3. se Not Empty Directory, chiama di nuovo cancella con la sottodirectory, ripeti da 1 a 3

esempio:

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

Per accedere alla Directory di archiviazione esterna, sono necessarie le seguenti autorizzazioni:

(Usa ContextCompat.checkSelfPermissione ActivityCompat.requestPermissions)

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

Metodo ricorsivo:

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

0

Ho messo questo anche se il suo ritmo elimina una cartella con qualsiasi struttura di directory.

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;

}

Spero che questo ti aiuti.


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

ecco la tua soluzione aggiornerà anche la galleria.


0

Ancora un altro modo (moderno) per risolverlo.

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

Su Android dall'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();
        }
    }
}

0

Sto usando questa funzione ricorsiva per fare il lavoro:

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 funzione controlla se si tratta di una directory o di un file.

Se è una directory controlla se ha file figlio, se ha file figlio si chiamerà di nuovo passando i bambini e ripetendo.

Se è un file, lo elimina.

(Non utilizzare questa funzione per cancellare la cache dell'app passando la directory cache perché eliminerà anche la directory cache in modo che l'app si blocchi in modo anomalo ... Se si desidera cancellare la cache, utilizzare questa funzione che non eliminerà il dir ci passi:

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

oppure puoi verificare se si tratta della directory cache usando:

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

Codice di esempio per cancellare la cache dell'app:

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

Ciao, buona giornata e programmazione: D

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.