Excluir diretórios recursivamente em Java

382

Existe uma maneira de excluir diretórios inteiros recursivamente em Java?

No caso normal, é possível excluir um diretório vazio. No entanto, quando se trata de excluir diretórios inteiros com conteúdo, não é mais tão simples assim.

Como você exclui diretórios inteiros com conteúdo em Java?

paweloque
fonte
4
File.delete () deve simplesmente retornar false ao chamá-lo com um diretório não vazio.
22710 Ben S
Se você estiver usando o Java 8, consulte a resposta do @ RoK.
Robin

Respostas:

462

Você deve conferir o commons-io do Apache . Possui uma classe FileUtils que fará o que você deseja.

FileUtils.deleteDirectory(new File("directory"));
Steve K
fonte
3
Essa função provavelmente envolve o código que Erickson forneceu em sua resposta.
paweloque
14
É um pouco mais completo. Ele lida com coisas como links simbólicos corretamente no Linux / Unix. svn.apache.org/viewvc/commons/proper/io/trunk/src/java/org/...
Steve K
11
@ Steve K, a URL está agora: svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/…
Richard EB
Por que adicionar outra dependência quando o Java tem uma instalação pronta para uso? Veja a resposta de RoK nesta página ou stackoverflow.com/questions/35988192/…
foo
190

Com o Java 7, podemos finalmente fazer isso com detecção confiável de links simbólicos. (Não considero que o commons-io do Apache tenha detecção confiável de links simbólicos no momento, pois ele não manipula links no Windows criados com mklink.)

Para o bem da história, aqui está uma resposta pré-Java 7, que segue links 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
fonte
11
File.delete () não possui essa funcionalidade.
22710 Ben S
14
@ Erickson: FileNotFoundException não é uma exceção ruim para uma falha de exclusão? Se o arquivo realmente não estiver mais lá, ele já deve ter sido excluído, o que significa que, semanticamente, a exclusão não falhou - não havia nada a fazer. E se falhou por algum outro motivo, não foi porque o arquivo não foi encontrado.
Lawrence Dol
46
Tenha MUITO CUIDADO . Isso desreferirá links simbólicos. Se você está em como o Linux, e tem uma pasta foocom um link foo/linkde tal forma que link->/, chamando delete(new File(foo)) irá eliminar o máximo de seu sistema de arquivos como o seu usuário tem permissão para !!
Miquel
4
@ Michel Isso não faz sentido - Por que queremos ter cuidado? Certamente, o objetivo do código fornecido é remover um diretório inteiro, que é o que parece fazer. Eu não entendo qual é o perigo aqui.
Joehot200
12
@ Joehot200 você está certo, chamar delete em um link simbólico de diretório não excluirá o diretório, apenas o link simbólico em si. A exclusão do diretório exigiria realmente seguir o link simbólico explicitamente usando ReadSymbolicLink . Foi mal! Bem localizado
Miquel
148

No Java 7+, você pode usar a Filesclasse. O código é muito simples:

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
fonte
2
Esta solução parece muito elegante e não contém lógica de passagem de diretório!
Zero3 28/11
11
"Para encontrar um mergulho de pérolas nas profundezas do oceano." Esta é de longe a solução mais limpa que encontrei. Tive que mergulhar fundo para encontrá-lo. Brilhante!
Basil Musa
20
"Código" NÃO é "muito simples" para simplesmente excluir um diretório :-) Mas, ei, essa é a melhor solução em java puro, eu acho.
Mat
11
Observe que a sobrecarga do walkFileTree usada aqui " não segue os links simbólicos ". (Javadoc: docs.oracle.com/javase/7/docs/api/java/nio/file/… )
Stephan
11
Você provavelmente deve chamar super.postVisitDirectory(dir, exc);seu postVisitDirectorymétodo para explodir se a caminhada não puder listar um diretório.
Tom Anderson
68

Solução de uma linha (Java8) para excluir todos os arquivos e diretórios recursivamente, incluindo o diretório inicial:

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

Usamos um comparador para ordem inversa, caso contrário, File :: delete não poderá excluir um diretório possivelmente não vazio. Portanto, se você deseja manter os diretórios e excluir apenas os arquivos, remova o comparador de classificado () ou remova a classificação completamente e adicione o filtro de arquivos:

Files.walk(Paths.get("c:/dir_to_delete/"))
                .filter(Files::isRegularFile)
                .map(Path::toFile)
                .forEach(File::delete);
RoK
fonte
11
Você precisa alterar a classificação no primeiro para .sorted (Comparator :: reverseOrder) para excluir todos os diretórios. Caso contrário, o diretório pai será ordenado antes do filho e, portanto, não será excluído, pois não está vazio. Ótima resposta para quem usa Java 8!
Robin
11
A maneira correta é .sorted(Comparator.reverseOrder())A sugestão Comparator::reverseOrderé que não funciona. Veja: stackoverflow.com/questions/43036611/…
user1156544
4
Robin, preste atenção no sinal de menos em "-o1.compareTo (o2)". É o mesmo que .sorted (Comparator.reverseOrder)
RoK
Files.walk é seqüencial? Ou essa resposta precisa forEachOrdered em vez de forEach para evitar a tentativa de excluir diretórios não vazios?
Silwing 30/10/19
Basta usar .sorted((f1, f2) -> f2.compareTo(f1)):, comparando f2com em f1vez de f1com f2.
Beto Neto
67

O Java 7 adicionou suporte para diretórios ambulantes com manipulação de link simbólico:

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

Eu uso isso como um fallback de métodos específicos da plataforma (neste código não testado ):

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

(O SystemUtils é do Apache Commons Lang . Processos é privado, mas seu comportamento deve ser óbvio.)

Trevor Robinson
fonte
Acho um problema com o Files.walkFileTree - é insuficiente para implementar uma versão de exclusão recursiva, na qual você continua excluindo arquivos até ficar sem opções. É adequado para uma versão fail-rápido, mas não rápido nem sempre é o que você quer (por exemplo, se você estiver limpando arquivos temporários, você quer apagar-agora, não deixar-rápido.)
Trejkaz
Não vejo por que isso é verdade. Você pode lidar com os erros da maneira que desejar - não precisa falhar rapidamente. O único problema que eu poderia prever é que ele pode não lidar com novos arquivos sendo criados durante a caminhada do diretório atual, mas essa é uma situação única, mais adequada para uma solução personalizada.
Trevor Robinson
11
Se você suprimir o erro do visitFile e chamar walkFileTree em um único arquivo que falhar, você não receberá nenhum erro (portanto, o visitFile deve propagar qualquer erro que ocorra.) Se você estiver excluindo um diretório e falhar ao excluir um arquivo, o único retorno de chamada chamado é postVisitDirectory. ou seja, ele não visita os outros arquivos no diretório se você receber um erro ao visitar um arquivo. É isso que eu quero dizer. Tenho certeza de que provavelmente existe uma maneira de contornar isso, mas quando chegamos a esse ponto já tínhamos escrito mais código do que uma rotina de exclusão recursiva tradicional, então decidimos não usá-lo.
21313 Trejkaz
Obrigado pelo seu primeiro código, foi útil para mim, mas tive que alterá-lo, porque não foi concluída uma deltree simples: tive que ignorar a exceção em "postVisitDirectory" e retornar CONTINUE independentemente, porque a árvore simples a seguir não pôde ser totalmente ser excluído: um diretório dentro do qual havia outro diretório dentro do qual havia um arquivo. Tudo isso tão simples / normal quanto possível, no Windows.
Dreamspace Presidente
Tudo começou a partir de uma java.nio.file.DirectoryNotEmptyException que recebi. Descobri o caso em que visitFileFailed é usado. Se sua estrutura de diretórios possui um link de tipo de junção no Windows. Isso pode causar dois problemas: *) Files.walkFileTree segue o link para a junção e exclui tudo. *) Se o diretório de destino da junção já estiver excluído, a análise do link pelo Files.walkFileTree falhará com NoSuchFileException, que é capturado em visitFileFailed.
Andrés Luuk
34

Acabei de ver que minha solução é mais ou menos a mesma de Erickson, apenas empacotada como um método estático. Deixe isso em algum lugar, é muito mais leve do que instalar todo o Apache Commons para algo que (como você pode ver) é bastante simples.

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

Uma solução com uma pilha e sem 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
fonte
2
+1 para usar uma pilha. Isso funcionará com diretórios que contêm níveis profundos de subdiretórios aninhados, enquanto as outras abordagens baseadas em pilha falharão.
Nathan Osman
4
Como você normalmente não tem problemas para aninhar algumas centenas de chamadas de método, acho que você provavelmente encontrará restrições de sistema de arquivos muito antes.
Bombe
2
Tenha cuidado com os list*métodos da classe java.io.File. Nos Javadocs: "Retorna nulo se esse nome de caminho abstrato não indicar um diretório ou se ocorrer um erro de E / S." Então: if (currList.length > 0) {se tornaif (null != currList && currList.length > 0) {
kevinarpe 11/11
11
Eu uso um ArrayDeque em vez de uma pilha que é um pouco mais rápida. (não sincronizado)
Wytze 30/10
15

Se você possui o Spring, pode usar o FileSystemUtils.deleteRecursively :

import org.springframework.util.FileSystemUtils;

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

A goiaba tinha Files.deleteRecursively(File)apoiado até a goiaba 9 .

Da goiaba 10 :

Descontinuada. Este método sofre de más condições de detecção e corrida de links simbólicos. Essa funcionalidade pode ser suportada adequadamente apenas através de um comando do sistema operacional como rm -rfou del /s. Este método está programado para ser removido do Guava no Guava versão 11.0.

Portanto, não existe esse método na goiaba 11 .

Andrew McKinlay
fonte
6
Que pena. Descascar parece um pouco bruto e não é portátil. Se a versão comum do Apache funcionar corretamente, presumivelmente não é impossível de implementar.
Andrew McKinlay
6
@andrew A implementação do Apache Commons deve ter problemas semelhantes aos que fazem com que o Guava remova sua implementação, consulte code.google.com/p/guava-libraries/issues/detail?id=365
orip
A versão apache commons detecta links simbólicos e simplesmente não atravessa os filhos do arquivo.
Ajax
5
O Guava 21.0 adicionou isso 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);
}

Ou se você deseja lidar com IOException:

Files.walk(directoryToDelete).
    sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
    forEach(p -> {
        try { Files.delete(p); }
        catch(IOException e) { /* ... */ }
      });
user3669782
fonte
2
Isso me ajudou a criar uma versão do Scala:Files.walk(path).iterator().toSeq.reverse.foreach(Files.delete)
James Ward
A classificação é realmente necessária? O walkmétodo já garante uma travessia em profundidade.
VGR
O comparador pode ser reciclado Collections.reverseOrder()para que seu código for (Path p : Files.walk(directoryToDelete).sorted(reverseOrder()).toArray(Path[]::new))suponha que ele tenha sido importado estaticamente.
namero999
@ namero999 Você quer dizer Comparator.reverseOrder? Files.walk(dir) .sorted(Comparator.reverseOrder()) .toArray(Path[]::new))
23417 Jeff Jeff
@ Jeff certeza de que você está certo, a maioria passou pela memória lá :)
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
fonte
5
Versão aprimorada com valor de retorno booleano e sem duplicação: pastebin.com/PqJyzQUx
Erik Kaplun 5/14
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
fonte
Código legal, mas há um erro, quando corrigido, funciona. A linha f.delete()abaixo deleteDirectory(f)lança NoSuchFileException porque o deleteDirectory(f)arquivo já foi excluído. Todo diretório se tornará um caminho quando passado deleteDirectory(f)e sendo excluído por path.delete(). Portanto, não precisamos f.delete()na if f.isDerectoryseção. Então, basta excluir f.delete();em deleteDirectory (f) e ele funcionará.
Trieu Nguyen
5

Duas maneiras de falhar com links simbólicos e o código acima ... e não sabemos a solução.

Caminho # 1

Execute isto para criar um teste:

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

Aqui você vê seu arquivo de teste e diretório de teste:

$ ls testfile dirtodelete
testfile

dirtodelete:
linktodelete

Em seguida, execute seu commons-io deleteDirectory (). Falha dizendo que o arquivo não foi encontrado. Não tenho certeza do que os outros exemplos fazem aqui. O comando rm do Linux simplesmente excluiria o link e rm -r no diretório também.

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

Caminho # 2

Execute isto para criar um teste:

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

Aqui você vê seu arquivo de teste e diretório de teste:

$ ls dirtodelete testdir
dirtodelete:
dirlinktodelete

testdir:
testfile

Em seguida, execute o commons-io deleteDirectory () ou o código de exemplo que as pessoas postaram. Exclui não apenas o diretório, mas seu arquivo de teste que está fora do diretório sendo excluído. (Desreferencia o diretório implicitamente e exclui o conteúdo). rm -r excluiria apenas o link. Você precisa usar algo como isso para excluir os arquivos referenciados: "find -L dirtodelete -type f -exec rm {} \;".

$ ls dirtodelete testdir
ls: cannot access dirtodelete: No such file or directory
testdir:
Pedro
fonte
4

Você poderia usar:

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

Exclui um arquivo, nunca lançando uma exceção. Se o arquivo for um diretório, exclua-o e todos os subdiretórios. A diferença entre File.delete () e este método é: Um diretório a ser excluído não precisa estar vazio. Nenhuma exceção é lançada quando um arquivo ou diretório não pode ser excluído.

Jan-Terje Sørensen
fonte
4

Uma solução ideal que lida com exceção de maneira consistente com a abordagem que uma exceção lançada de um método sempre deve descrever o que esse método estava tentando (e falhou):

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

Em projetos legados, preciso criar código Java nativo. Eu crio esse código semelhante ao código Paulitex. Veja que:

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

E o teste de unidade:

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

O código abaixo exclui recursivamente todo o conteúdo de uma determinada pasta.

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

Aqui está um método principal básico que aceita um argumento de linha de comando; talvez você precise anexar sua própria verificação de erro ou moldá-lo da maneira que achar melhor.

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 ajude!

cola
fonte
1

Talvez uma solução para esse problema possa ser reimplementar o método delete da classe File usando o código da resposta 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
fonte
11
Eu acho que foi implementado como para imitar o comportamento da maioria dos utilitários de shell de comando como "rm", "rmdir" e "del". Das duas alternativas, a implementação atual definitivamente minimiza o potencial geral de surpresa (e raiva). Isso não vai mudar.
22610 erickson
4
Geralmente, os únicos pacotes Java JRE que vejo estendidos são do Swing. Geralmente, estender outras classes, como java.io.File, é uma péssima idéia, pois tem a possibilidade de fazer com que as coisas ajam de maneiras inesperadas.
22420 Eddie
1

Sem o Commons IO e <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
fonte
0

Embora os arquivos possam ser facilmente excluídos usando file.delete (), é necessário que os diretórios estejam vazios para serem excluídos. Use recursão para fazer isso facilmente. Por exemplo:

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

codifiquei essa rotina que possui três critérios de segurança para um uso mais 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
fonte
0

Bem, vamos assumir um exemplo,

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 mais informações, consulte os recursos abaixo

Excluir diretório

Shiva
fonte
0

rm -rfteve muito mais desempenho do que FileUtils.deleteDirectory.

Após extensos testes comparativos, descobrimos que o uso rm -rfera várias vezes mais rápido que o usoFileUtils.deleteDirectory .

Obviamente, se você tem um diretório pequeno ou simples, isso não importa, mas no nosso caso, tínhamos vários gigabytes e subdiretórios profundamente aninhados, onde levaria mais de 10 minutos FileUtils.deleteDirectorye apenas 1 minuto rm -rf.

Aqui está nossa implementação Java áspera para fazer isso:

// 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 a pena tentar se você estiver lidando com diretórios grandes ou complexos.

Joshua Pinter
fonte
Isso funciona entre plataformas?
OneCricketeer
@ cricket_007 Quais plataformas?
Joshua Pinter
Janelas? OpenWrt? BSD?
OneCricketeer
11
@ cricket_007 Definitivamente não é o Windows. Isso foi testado e usado no Android e macOS.
Joshua Pinter
0

Goiaba oferece uma one-liner: MoreFiles.deleteRecursively().

Ao contrário de muitos dos exemplos compartilhados, ele é responsável por links simbólicos e (por padrão) não exclui arquivos fora do caminho fornecido.

dimo414
fonte