Como excluir uma pasta e conteúdo inteiros?

187

Desejo que os usuários do meu aplicativo possam excluir a pasta DCIM (que está localizada no cartão SD e contém subpastas).

Isso é possível? Em caso afirmativo, como?

Principiante
fonte
1
que não seja a abordagem de exclusão de baixo para cima recursiva?
Sarwar Erfan
Se você tiver um diretório muito grande ou complexo, use-o em rm -rf directoryvez de FileUtils.deleteDirectory. Após o benchmarking, descobrimos que era várias vezes mais rápido. Confira um exemplo de implementação aqui: stackoverflow.com/a/58421350/293280
Joshua Pinter

Respostas:

301

Deixe-me dizer a primeira coisa que você não pode excluir a pasta DCIM porque é uma pasta do sistema. Ao excluí-lo manualmente no telefone, o conteúdo dessa pasta será excluído, mas não a pasta DCIM. Você pode excluir seu conteúdo usando o método abaixo:

Atualizado conforme os comentários

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
fonte
3
erm como declarar o que é dir?
iniciante
im basicamente tentando apagar todas as fotos para que importa doesnt é DCIM não é eliminado enquanto as fotos são ... por isso mesmo apagar 100MEDIA a pasta dentro deste iria fazer o trabalho
Beginner
1
você deve declarar o diretório usando o caminho da pasta dicm: use file r = file (path);
Chikka.anddev
3
arquivo usado dir = novo arquivo (Environment.getExternalStorageDirectory () + "/ DCIM / 100MEDIA");
Iniciante
1
@chiragshah Depois de excluir uma pasta e recriar a pasta, resultando na criação de um arquivo desconhecido com o mesmo nome de pasta mencionado.E se estou tentando acessar esse arquivo, está lançando uma exceção como Recurso ou dispositivo ocupado . arquivo onde eu encontrei MD5 Assinatura: Operação Falha
sha
529

Você pode excluir arquivos e pastas recursivamente assim:

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

    fileOrDirectory.delete();
}
teedyay
fonte
21
Não fiz testes de eficiência, mas acredito que o meu é mais robusto. O chirag's funcionará no caso específico da pasta DCIM, onde as pastas no DCIM devem conter apenas arquivos (ou seja, as pastas no DCIM normalmente não contêm subpastas). Minha versão excluirá pastas aninhadas em qualquer profundidade. É possível que o usuário tenha modificado o conteúdo do seu cartão SD para que o DCIM contenha pastas aninhadas mais profundamente (por exemplo DCIM\foo\bar\pic.jpg). Nesse caso, o código do chirag falhará.
teedyay
2
Uma pergunta que um colega me fez: O que acontece se uma pasta tiver um link simbólico e você executar esse pedaço de código?
P4u144
1
@ p4u144 Dê a seu colega mais cinco por ser um gênio! Bem manchado! Para ser sincero, não sei se esse código respeitará ou seguirá os links simbólicos, mas, se o fizer, você terá um loop infinito. Você gosta de testá-lo?
teedyay
8
@ p4u144 Não se preocupe com links simbólicos. "Com links simbólicos, o link é excluído e não o destino do link." de docs.oracle.com/javase/tutorial/essential/io/delete.html
corbin
3
Existe um NPE possível aqui: fileOrDirectory.listFiles()pode retornar nullse houver erro de E / S ao ler os arquivos. Isso está claramente indicado na documentação: developer.android.com/reference/java/io/File.html#listFiles ()
Brian Yencho 6/18
67

Podemos usar os argumentos da linha de comando para excluir uma pasta inteira e seu conteúdo.

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

Exemplo de uso do código acima:

deleteFiles("/sdcard/uploads/");
xinaxino
fonte
2
parece bom, você sabe se isso é síncrono ou assíncrono? A documentação não diz: developer.android.com/reference/java/lang/…
Alguém em algum lugar
2
Péssima ideia. Por que fazê-lo na casca?
noamtm
1
@SomeoneSomewhere async docs.oracle.com/javase/7/docs/api/java/lang/…
sudocoder
34

No Kotlin você pode usar a deleteRecursively()extensão do kotlin.iopacote

val someDir = File("/path/to/dir")
someDir.deleteRecursively()
Dima Rostopira
fonte
2
Em Java, você pode usar FilesKt.deleteRecursively(new File("/path/to/dir"));se você estiver usando o kotlin-stdlib
Joonsoo 26/12/19
Este comando excluirá o diretório "/ dir" com o conteúdo dentro ou apenas o conteúdo dentro do diretório "/ dir" e o diretório permanecerá lá?
Bhimbim 21/02
1
@Bhimbim me deixe o Google Docs para você "Exclua este arquivo com todos os seus filhos". Portanto, o diretório será excluído e o conteúdo
Dima Rostopira
Obrigado @DimaRostopira!.
Bhimbim 25/02
Kotlin para o resgate!
Tobi Oyelekan
15

use o método abaixo para excluir todo o diretório principal que contém arquivos e seu subdiretório. Depois de chamar esse método, chame novamente o diretório delete () do seu diretório 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
fonte
De todas as respostas, esta é a ÚNICA resposta real que exclui o diretório também após excluir os arquivos nele.
zeeshan
File file = new File (Environment.getExternalStorageDirectory () + separador + "nome_da_pasta" + separador); deleteDir (arquivo); Sim, isso funciona. Obrigado :)
ashishdhiman2007
14

Sua abordagem é decente para uma pasta que contém apenas arquivos, mas se você estiver procurando por um cenário que também contenha subpastas, a recursão será necessária.

Além disso, você deve capturar o valor de retorno para garantir que você tenha permissão para excluir o arquivo

e inclua

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

no seu manifesto

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
fonte
5
Isso pode ser mais fácil se você usar o (File currentFile: file.listFiles ()) {
Thorben
8

Existem muitas respostas, mas decidi adicionar as minhas, porque é um pouco diferente. É baseado em OOP;)

Criei a classe DirectoryCleaner , que me ajuda sempre que preciso limpar algum diretório.

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

    }
}

Pode ser usado para resolver esse problema da próxima maneira:

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

Se você não precisar excluir as coisas recursivamente, tente algo como isto:

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
fonte
6

Você não pode excluir o diretório se ele tiver subdiretórios ou arquivos em Java. Experimente esta solução simples de duas linhas. Isso excluirá o diretório e os concursos dentro do diretório.

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

Adicione esta linha no arquivo gradle e sincronize o projeto

compile 'org.apache.commons:commons-io:1.3.2'  
Vigneswaran A
fonte
Como um liner 2, é simples. Mas instalar uma biblioteca inteira para utilizar apenas um de seus métodos parece ineficiente. Use isso em vez disso
Kathir
A ponta da pastilha salvou minha 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();
    }
}
Deep Verma
fonte
4

De acordo com a documentação :

Se esse nome de caminho abstrato não indicar um diretório, esse método retornará nulo.

Portanto, você deve verificar se listFilesé nulle continuar apenas se não for

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.
fonte
1
Essa deve ser a resposta aceita. Funciona como um encanto!
MSeiz5
3

Isto é o que eu faço ... (conciso e testado)

    ...
    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
fonte
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
fonte
2

Maneira simples de excluir todos os arquivos do diretório:

É uma função genérica para excluir todas as imagens do diretório chamando apenas

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();
            }
        }    
    } 
Sagar Chorage
fonte
2

Código mais seguro que eu conheço:

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 se o arquivo existe, trata nulos, verifica se o diretório foi realmente excluído

Gary Davies
fonte
2

Versão curta koltin

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

Aqui está uma implementação não recursiva, apenas por diversão:

/**
 * 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
fonte
1

Isso (tenta excluir todos os subarquivos e subdiretórios, incluindo o diretório fornecido) :

  1. E se File excluir
  2. E se Empty Directory excluir
  3. se Not Empty Directory, chame delete novamente com o subdiretório, repita 1 a 3

exemplo:

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

Para obter acesso ao Diretório de armazenamento externo, você precisa das seguintes permissões:

(Use ContextCompat.checkSelfPermissione 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
fonte
0

Eu coloquei este, embora seja um passo, ele apaga uma pasta com qualquer estrutura de diretório.

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 isto ajude.

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

aqui está sua solução, ela também atualizará a galeria.

Bilal Mustafa
fonte
0

Mais uma maneira (moderna) de resolvê-lo.

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

No Android desde a 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
fonte
0

Estou usando esta função recursiva para fazer o trabalho:

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

A função verifica se é um diretório ou um arquivo.

Se for um diretório, verifica se há arquivos filho, se ele tiver arquivos filhos se chamará novamente passando os filhos e repetindo.

Se for um arquivo, exclua-o.

(Não use esta função para limpar o cache do aplicativo passando o diretório de cache, pois ele também excluirá o diretório de cache, para que o aplicativo falhe ... Se você deseja limpar o cache, use esta função que não excluirá o diretório dir você passa para ele:

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 você pode verificar se é o diretório do cache usando:

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

Exemplo de código para limpar o cache do aplicativo:

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

Tchau, tenha um bom dia e codificação: D

Z3R0
fonte