Comment supprimer un dossier et un contenu entiers?

187

Je souhaite que les utilisateurs de mon application puissent supprimer le dossier DCIM (qui se trouve sur la carte SD et contient des sous-dossiers).

Est-ce possible, si oui, comment?

Débutant
la source
1
autre que l'approche de suppression récursive ascendante?
Sarwar Erfan
Si vous avez un répertoire très volumineux ou complexe, vous devez utiliser à la rm -rf directoryplace de FileUtils.deleteDirectory. Après l'analyse comparative, nous avons constaté que c'était plusieurs fois plus rapide. Découvrez un exemple d'implémentation ici: stackoverflow.com/a/58421350/293280
Joshua Pinter

Réponses:

301

Laissez-moi vous dire tout d'abord que vous ne pouvez pas supprimer le dossier DCIM car il s'agit d'un dossier système. Lorsque vous le supprimez manuellement sur le téléphone, il supprimera le contenu de ce dossier, mais pas le dossier DCIM. Vous pouvez supprimer son contenu en utilisant la méthode ci-dessous:

Mis à jour selon les commentaires

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
la source
3
Euh, comment déclarer ce que dir est?
Débutant le
J'essaie essentiellement de supprimer toutes les photos, donc peu importe que DCIM ne soit pas supprimé tant que les photos le sont ... donc même la suppression de 100MEDIA du dossier dans ce dossier ferait l'affaire
Débutant
1
vous devez déclarer le répertoire en utilisant le chemin du dossier dicm: utilisez le fichier r = fichier (chemin);
chikka.anddev
3
utilisé File dir = nouveau fichier (Environment.getExternalStorageDirectory () + "/ DCIM / 100MEDIA");
Débutant le
1
@chiragshah Après avoir supprimé un dossier et recréé le dossier, ce qui a entraîné la création d'un fichier inconnu avec le même nom de dossier mentionné.Et si j'essaie d'accéder à ce fichier, il lance une exception telle que Ressource ou périphérique occupé.J'ai également vérifié les propriétés de fichier où j'ai trouvé Signature MD5: Échec de l'opération
sha
529

Vous pouvez supprimer des fichiers et des dossiers de manière récursive comme ceci:

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

    fileOrDirectory.delete();
}
teedyay
la source
21
Je n'ai fait aucun test d'efficacité, mais je pense que le mien est plus robuste. chirag fonctionnera pour le cas spécifique du dossier DCIM, où les dossiers dans DCIM ne doivent contenir que des fichiers (c'est-à-dire que les dossiers dans DCIM ne contiennent normalement aucun sous-dossier). Ma version supprimera les dossiers imbriqués à n'importe quelle profondeur. Il est possible que l'utilisateur ait modifié le contenu de sa carte SD pour que DCIM contienne des dossiers imbriqués plus profondément (par exemple DCIM\foo\bar\pic.jpg), auquel cas le code de chirag échouera.
teedyay
2
Une question qu'un collègue m'a posée: que se passe-t-il si un dossier a un lien symbolique sur lui-même et que vous exécutez ce morceau de code?
p4u144
1
@ p4u144 Donnez à votre collègue un high-five pour être un génie! Bien repéré! Pour être honnête, je ne sais pas si ce code respecterait et suivrait les liens symboliques, mais si c'est le cas, vous aurez une boucle infinie. Envie de le tester?
teedyay
8
@ p4u144 Pas de soucis pour les liens symboliques. "Avec les liens symboliques, le lien est supprimé et non la cible du lien." de docs.oracle.com/javase/tutorial/essential/io/delete.html
corbin
3
Il y a un NPE possible ici: fileOrDirectory.listFiles()peut retourner nulls'il y a une erreur d'E / S lors de la lecture des fichiers. Ceci est clairement indiqué dans la documentation: developer.android.com/reference/java/io/File.html#listFiles ()
Brian Yencho
67

Nous pouvons utiliser les arguments de la ligne de commande pour supprimer un dossier entier et son contenu.

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

Exemple d'utilisation du code ci-dessus:

deleteFiles("/sdcard/uploads/");
Xinaxino
la source
2
semble bon, savez-vous si c'est synchrone ou asynchrone? La documentation ne dit pas: developer.android.com/reference/java/lang/…
Someone Somewhere
2
Mauvaise idée. Pourquoi le faire sur la coque?
noamtm
1
@SomeoneSomewhere async docs.oracle.com/javase/7/docs/api/java/lang/…
sudocoder
34

Dans Kotlin, vous pouvez utiliser l' deleteRecursively()extension du kotlin.iopackage

val someDir = File("/path/to/dir")
someDir.deleteRecursively()
Dima Rostopira
la source
2
En Java, vous pouvez utiliser FilesKt.deleteRecursively(new File("/path/to/dir"));si vous utilisez kotlin-stdlib
Joonsoo
Cette commande supprimera le répertoire "/ dir" avec le contenu à l'intérieur ou simplement le contenu dans le répertoire "/ dir" et le répertoire y restera?.
Bhimbim le
1
@Bhimbim lemme google docs pour vous "Supprimer ce fichier avec tous ses enfants.". Ainsi, le répertoire sera supprimé ainsi que le contenu
Dima Rostopira
Merci @DimaRostopira!.
Bhimbim le
kotlin à la rescousse!
Tobi Oyelekan
15

utilisez la méthode ci-dessous pour supprimer tout le répertoire principal qui contient des fichiers et son sous-répertoire. Après avoir appelé à nouveau cette méthode, appelez à nouveau le répertoire delete () de votre répertoire 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();
}
Android
la source
Parmi toutes les réponses, c'est la SEULE vraie réponse qui supprime également le répertoire après avoir supprimé les fichiers qu'il contient.
zeeshan
Fichier fichier = nouveau fichier (Environment.getExternalStorageDirectory () + séparateur + "nom_dossier" + séparateur); deleteDir (fichier); Oui, cela fonctionne. Thanks :)
ashishdhiman2007
14

Votre approche est décente pour un dossier qui ne contient que des fichiers, mais si vous recherchez un scénario contenant également des sous-dossiers, la récursivité est nécessaire

Vous devez également capturer la valeur de retour du retour pour vous assurer que vous êtes autorisé à supprimer le fichier

et inclure

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

dans ton manifeste

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
la source
5
Cela pourrait être plus facile si vous utilisez pour (File currentFile: file.listFiles ()) {
Thorben
8

Il y a beaucoup de réponses, mais j'ai décidé d'ajouter la mienne, car c'est un peu différent. Il est basé sur la POO;)

J'ai créé la classe DirectoryCleaner , qui m'aide à chaque fois que j'ai besoin de nettoyer un répertoire.

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

    }
}

Il peut être utilisé pour résoudre ce problème de la manière suivante:

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

Si vous n'avez pas besoin de supprimer des éléments de manière récursive, vous pouvez essayer quelque chose comme ceci:

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
la source
6

Vous ne pouvez pas supprimer le répertoire s'il contient des sous-répertoires ou des fichiers en Java. Essayez cette solution simple en deux lignes. Cela supprimera le répertoire et les concours à l'intérieur du répertoire.

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

Ajoutez cette ligne dans le fichier gradle et synchronisez le projet

compile 'org.apache.commons:commons-io:1.3.2'  
Vigneswaran A
la source
En 2 lignes, c'est simple. Mais installer une bibliothèque entière pour n'utiliser qu'une seule de ses méthodes semble inefficace. Utilisez ceci à la place
Kathir
Gradle insert tip m'a sauvé la vie.
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 profond
la source
4

Selon la documentation :

Si ce chemin abstrait ne désigne pas de répertoire, cette méthode renvoie null.

Vous devriez donc vérifier si listFilesc'est nullet ne continuer que si ce n'est pas le cas

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());
}
HB.
la source
1
Cela devrait être la réponse acceptée. Fonctionne comme un charme!
MSeiz5
3

C'est ce que je fais ... (laconique et testé)

    ...
    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
la source
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
la source
2

Un moyen simple de supprimer tous les fichiers du répertoire:

C'est une fonction générique pour supprimer toutes les images du répertoire en appelant uniquement

deleteAllImageFile (contexte);

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

Code le plus sûr que je connaisse:

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

Vérifie que le fichier existe, gère les valeurs nulles, vérifie que le répertoire a bien été supprimé

Gary Davies
la source
2

Version courte koltin

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

Voici une implémentation non récursive, juste pour le plaisir:

/**
 * 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
la source
1

Ceci (tente de supprimer tous les sous-fichiers et sous-répertoires, y compris le répertoire fourni) :

  1. Si File , supprimer
  2. Si Empty Directory , supprimer
  3. si Not Empty Directory, appelez à nouveau delete avec le sous-répertoire, répétez 1 à 3

exemple:

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

Pour accéder au répertoire de stockage externe, vous avez besoin des autorisations suivantes:

(Utiliser ContextCompat.checkSelfPermissionet ActivityCompat.requestPermissions)

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

Méthode récursive:

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
la source
0

J'ai mis celui-ci bien qu'il supprime un dossier avec n'importe quelle structure de répertoire.

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;

}

J'espère que cela t'aides.

user2288580
la source
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) {
    }
}

voici votre solution, elle rafraîchira également la galerie.

Bilal Mustafa
la source
0

Encore une autre façon (moderne) de le résoudre.

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

Sur Android depuis l'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
la source
0

J'utilise cette fonction récursive pour faire le travail:

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 fonction vérifie s'il s'agit d'un répertoire ou d'un fichier.

Si c'est un répertoire vérifie s'il a des fichiers enfants, s'il a des fichiers enfants, il s'appellera à nouveau en passant les enfants et en se répétant.

S'il s'agit d'un fichier, supprimez-le.

(N'utilisez pas cette fonction pour vider le cache de l'application en passant le répertoire du cache car cela supprimera également le répertoire du cache et l'application plantera ... Si vous souhaitez effacer le cache, vous utilisez cette fonction qui ne supprimera pas le dir vous lui passez:

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

ou vous pouvez vérifier s'il s'agit du répertoire de cache en utilisant:

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

Exemple de code pour vider le cache de l'application:

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

Au revoir, bonne journée et codage: D

Z3R0
la source