Elimina le directory in modo ricorsivo in Java


382

C'è un modo per eliminare ricorsivamente intere directory in Java?

Nel caso normale è possibile eliminare una directory vuota. Tuttavia, quando si tratta di eliminare intere directory con contenuti, non è più così semplice.

Come si eliminano intere directory con contenuti in Java?


4
File.delete () dovrebbe semplicemente restituire false dopo averlo chiamato con una directory non vuota.
Ben S,

Se stai usando Java 8, vedi la risposta di @ RoK.
Robin,

Risposte:


462

Dovresti dare un'occhiata al commons-io di Apache . Ha una classe FileUtils che farà quello che vuoi.

FileUtils.deleteDirectory(new File("directory"));

3
Questa funzione probabilmente include il codice fornito da Erickson nella sua risposta.
paweloque,

14
È un po 'più approfondito. Gestisce cose come i collegamenti simbolici correttamente su Linux / Unix. svn.apache.org/viewvc/commons/proper/io/trunk/src/java/org/…
Steve K



Perché aggiungere un'altra dipendenza quando Java ha una funzione pronta all'uso? Vedi la risposta di RoK in questa pagina o stackoverflow.com/questions/35988192/…
foo

190

Con Java 7, possiamo finalmente farlo con un rilevamento affidabile del collegamento simbolico. (Non considero i comuni di Apache in questo momento avere un rilevamento affidabile dei collegamenti simbolici, poiché non gestisce i collegamenti su Windows creati conmklink .)

Per motivi di storia, ecco una risposta pre-Java 7, che segue i collegamenti simbolici.

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

11
File.delete () non ha questa funzionalità.
Ben S,

14
@Erickson: FileNotFoundException non è una scarsa eccezione per un errore di eliminazione? Se il file non è più effettivamente presente, deve essere già stato eliminato, il che significa che, semanticamente, l'eliminazione non ha avuto esito negativo: non aveva nulla da fare. E se non è riuscito per qualche altro motivo, non è stato perché il file non è stato trovato.
Lawrence Dol,

46
Sii MOLTO ATTENTO . Ciò dereferirà collegamenti simbolici. Se sei su, ad esempio, Linux, e hai una cartella foocon un collegamento foo/linktale link->/, la chiamata delete(new File(foo)) eliminerà tanto del tuo filesystem quanto il tuo utente è autorizzato a !!
Miquel,

4
@Miquel Non ha senso: perché dovremmo stare attenti? Sicuramente il punto del codice fornito è rimuovere un'intera directory, che è ciò che sembra fare. Non capisco quale sia il pericolo qui.
Joehot200

12
@ Joehot200 hai ragione, chiamare eliminando su un link simbolico di directory non cancellerà la directory, ma solo il link simbolico stesso. L'eliminazione della directory richiederebbe in realtà di seguire esplicitamente il link simbolico utilizzando ReadSymbolicLink . Colpa mia! Ben notato
Miquel,

148

In Java 7+ è possibile utilizzare la Filesclasse. Il codice è molto semplice:

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

2
Questa soluzione sembra molto elegante e non contiene alcuna logica di attraversamento di directory!
Zero3,

1
"Per trovare un tuffo di perle in profondità nell'oceano.". Questa è di gran lunga la soluzione più accurata che ho trovato. Ho dovuto immergermi in profondità per trovarlo. Brillante!
Basil Musa,

20
"Il codice è" NON "molto semplice" per eliminare semplicemente una directory :-) Ma ehi, questa è la soluzione migliore in Java puro, credo.
Mat

1
Si noti che il sovraccarico walkFileTree utilizzato qui " non segue i collegamenti simbolici ". (Javadoc: docs.oracle.com/javase/7/docs/api/java/nio/file/… )
Stephan

1
Probabilmente dovresti chiamare il super.postVisitDirectory(dir, exc);tuo postVisitDirectorymetodo, per esplodere se il walk non è in grado di elencare una directory.
Tom Anderson

68

Soluzione one-liner (Java8) per eliminare tutti i file e le directory in modo ricorsivo inclusa la directory di avvio:

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

Usiamo un comparatore per ordine inverso, altrimenti File :: delete non sarà in grado di eliminare eventualmente directory non vuote. Quindi, se vuoi mantenere le directory ed eliminare solo i file, rimuovi il comparatore in sort () o rimuovi completamente l'ordinamento e aggiungi il filtro file:

Files.walk(Paths.get("c:/dir_to_delete/"))
                .filter(Files::isRegularFile)
                .map(Path::toFile)
                .forEach(File::delete);

1
È necessario modificare l'ordinamento nel primo in .sorted (Comparator :: reverseOrder) per eliminare tutte le directory. Altrimenti la directory padre viene ordinata prima del figlio e quindi non verrà eliminata poiché non è vuota. Ottima risposta per chi usa Java 8!
Robin,

1
Il modo corretto è .sorted(Comparator.reverseOrder())la suggestione Comparator::reverseOrdernon non funziona. Vedi: stackoverflow.com/questions/43036611/...
user1156544

4
Robin, presta attenzione al segno meno in "-o1.compareTo (o2)". È lo stesso di .sorted (Comparator.reverseOrder)
RoK

Files.walk è sequenziale? O questa risposta ha bisogno di OachOrdered anziché di Oach per evitare di provare a eliminare le directory non vuote?
Silwing

Basta usare .sorted((f1, f2) -> f2.compareTo(f1)):, confrontando f2con f1anziché f1con f2.
Beto Neto,

67

Java 7 ha aggiunto il supporto per le directory walking con gestione dei collegamenti simbolici:

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

Lo uso come fallback da metodi specifici della piattaforma (in questo codice non testato ):

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

(SystemUtils proviene da Apache Commons Lang . I processi sono privati ​​ma il suo comportamento dovrebbe essere ovvio.)


Trovo un problema con Files.walkFileTree: non è sufficiente per implementare una versione di eliminazione ricorsiva in cui si continua a eliminare i file fino a quando non si esauriscono le opzioni. È adeguato per una versione fail-fast, ma fail-fast non è sempre quello che vuoi (ad esempio se stai ripulendo i file temporanei, vuoi eliminare-ora, non fail-fast.)
Trejkaz

Non vedo perché sia ​​vero. Puoi gestire gli errori nel modo che preferisci: non devi fallire rapidamente. L'unico problema che potrei prevedere è che potrebbe non gestire i nuovi file creati durante il percorso della directory corrente, ma questa è una situazione unica più adatta a una soluzione personalizzata.
Trevor Robinson,

1
Se si elimina l'errore da visitFile e si chiama walkFileTree su un singolo file che non riesce, non si ottiene alcun errore (quindi visitFile deve propagare qualsiasi errore che si verifica.) Se si elimina una directory e non si riesce a eliminare un file, l'unico callback chiamato è postVisitDirectory. cioè, non visita gli altri file nella directory se si verifica un errore durante la visita di un file. Questo è ciò che intendo. Sono sicuro che probabilmente c'è un modo per aggirare questo problema, ma quando siamo arrivati ​​a questo punto avevamo già scritto più codice di una routine di eliminazione ricorsiva tradizionale, quindi abbiamo deciso di non usarlo.
Trejkaz,

Grazie per il tuo primo codice, mi è stato utile, ma ho dovuto cambiarlo, perché non ha completato un semplice deltree: ho dovuto ignorare l'eccezione in "postVisitDirectory" e restituire CONTINUE indipendentemente dal fatto che il seguente albero semplice non poteva completamente essere eliminato: una directory all'interno della quale c'era un'altra directory all'interno della quale c'era un file. Tutto ciò che è semplice / normale, su Windows.
Presidente di Dreamspace,

Tutto è iniziato da un java.nio.file.DirectoryNotEmptyException che ho ottenuto. Ho scoperto il caso in cui viene utilizzato visitFileFailed. Se la struttura della directory ha un collegamento del tipo di giunzione in Windows. Ciò può causare 2 problemi: *) Files.walkFileTree segue il collegamento nell'incrocio ed elimina tutto lì. *) Se la directory di destinazione del junction è già stata eliminata, l'analisi del collegamento da Files.walkFileTree non riesce con NoSuchFileException che viene rilevato in visitFileFailed.
Andres Luuk,

34

Ho appena visto che la mia soluzione è più o meno la stessa di quella di Erickson, appena confezionata come metodo statico. Lascialo da qualche parte, è molto più leggero rispetto all'installazione di Apache Commons per qualcosa che (come puoi vedere) è abbastanza semplice.

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

20

Una soluzione con uno stack e senza metodi ricorsivi:

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

2
+1 per l'utilizzo di uno stack. Funzionerà con le directory che contengono livelli profondi di sottodirectory nidificate mentre gli altri approcci basati su stack falliranno.
Nathan Osman,

4
Visto che di solito non hai problemi a annidare un paio di centinaia di chiamate di metodo, penso che probabilmente ti imbatterai in restrizioni del filesystem molto prima.
Bombe

2
Fai attenzione ai list*metodi per la classe java.io.File. Da Javadocs: "Restituisce null se questo percorso astratto non indica una directory o se si verifica un errore I / O." Quindi: if (currList.length > 0) {diventaif (null != currList && currList.length > 0) {
kevinarpe l'

1
Uso un ArrayDeque invece di uno Stack leggermente più veloce. (non sincronizzato)
Wytze,


15

Guava aveva Files.deleteRecursively(File)supportato fino a Guava 9 .

Da Guava 10 :

Deprecato. Questo metodo soffre di cattive condizioni di rilevazione e collegamento simbolico. Questa funzionalità può essere supportata opportunamente solo sborsando a un comando del sistema operativo come rm -rfo del /s. Questo metodo è programmato per essere rimosso da Guava nella versione 11.0 di Guava.

Pertanto, non esiste tale metodo in Guava 11 .


6
Peccato. Sgridare sembra un po 'rozzo e non portatile. Se la versione di Apache commons funziona correttamente, presumibilmente non è impossibile implementarla.
Andrew McKinlay

6
@andrew L'implementazione di Apache Commons dovrebbe avere problemi simili a quelli che causano a Guava la rimozione della loro implementazione, vedi code.google.com/p/guava-libraries/issues/detail?id=365
orip

La versione di Apache Commons rileva i collegamenti simbolici e semplicemente non attraversa i figli del file.
Ajax

5
Guava 21.0 ha aggiunto questo come 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);
}

O se vuoi gestire IOException:

Files.walk(directoryToDelete).
    sorted((a, b) -> b.compareTo(a)). // reverse; files before dirs
    forEach(p -> {
        try { Files.delete(p); }
        catch(IOException e) { /* ... */ }
      });

2
Questo mi ha aiutato a trovare una versione alla Scala:Files.walk(path).iterator().toSeq.reverse.foreach(Files.delete)
James Ward,

L'ordinamento è davvero necessario? Il walkmetodo garantisce già un attraversamento in profondità.
VGR,

Il comparatore potrebbe essere riciclato in Collections.reverseOrder()modo che il codice for (Path p : Files.walk(directoryToDelete).sorted(reverseOrder()).toArray(Path[]::new))presuma che sia stato importato staticamente.
namero999,

@ namero999 Intendi Comparator.reverseOrder? Files.walk(dir) .sorted(Comparator.reverseOrder()) .toArray(Path[]::new))
Jeff,

@Jeff abbastanza sicuro che tu abbia ragione, per lo più è andato a memoria 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();
}

5
Versione avanzata con valore di ritorno booleano e nessuna duplicazione: pastebin.com/PqJyzQUx
Erik Kaplun

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

Bel codice, ma c'è un bug, una volta risolto, funziona. La riga f.delete()sotto deleteDirectory(f)genererà NoSuchFileException perché deleteDirectory(f)elimina già quel file. Ogni directory diventerà un percorso una volta passata deleteDirectory(f)e cancellata da path.delete(). Pertanto, non è necessario f.delete()nella if f.isDerectorysezione. Quindi, basta eliminare f.delete();in deleteDirectory (f) e funzionerà.
Trieu Nguyen

5

Due modi per fallire con i collegamenti simbolici e il codice sopra ... e non conosco la soluzione.

Modo n. 1

Esegui questo per creare un test:

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

Qui puoi vedere il tuo file di test e la directory di test:

$ ls testfile dirtodelete
testfile

dirtodelete:
linktodelete

Quindi esegui commons-io deleteDirectory (). Si arresta in modo anomalo dicendo che il file non è stato trovato. Non sono sicuro di cosa facciano gli altri esempi qui. Il comando Linux rm eliminerebbe semplicemente il collegamento e anche rm -r nella directory.

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

Modo n. 2

Esegui questo per creare un test:

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

Qui puoi vedere il tuo file di test e la directory di test:

$ ls dirtodelete testdir
dirtodelete:
dirlinktodelete

testdir:
testfile

Quindi esegui commons-io deleteDirectory () o il codice di esempio pubblicato dagli utenti. Elimina non solo la directory, ma il file di test che si trova all'esterno della directory da eliminare. (Dereferenzia implicitamente la directory ed elimina i contenuti). rm -r eliminerebbe solo il collegamento. È necessario utilizzare qualcosa del genere eliminare i file con riferimento: "find -L dirtodelete -type f -exec rm {} \;".

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

4

Puoi usare:

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

Elimina un file, senza mai generare un'eccezione. Se il file è una directory, eliminalo e tutte le sottodirectory. Le differenze tra File.delete () e questo metodo sono: Una directory da cancellare non deve essere vuota. Non vengono generate eccezioni quando non è possibile eliminare un file o una directory.


4

Una soluzione ottimale che gestisce l'eccezione coerentemente con l'approccio che un'eccezione generata da un metodo dovrebbe sempre descrivere ciò che quel metodo stava cercando (e non è riuscito) di fare:

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

3

Nei progetti legacy, devo creare un codice Java nativo. Creo questo codice simile al codice Paulitex. Guarda quello:

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 il test unitario:

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

}

3

Il codice seguente elimina in modo ricorsivo tutto il contenuto di una determinata cartella.

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

2

Ecco un metodo principale di bare bones che accetta un argomento della riga di comando, potrebbe essere necessario aggiungere il tuo controllo degli errori o modellarlo come ritieni opportuno.

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

Spero che aiuti!


1

Forse una soluzione a questo problema potrebbe essere quella di reimplementare il metodo di eliminazione della classe File utilizzando il codice dalla risposta di 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();
    }
  }
}

1
Penso che sia implementato per imitare il comportamento della maggior parte delle utility della shell dei comandi come "rm", "rmdir" e "del". Delle due alternative, l'attuale implementazione minimizza definitivamente il potenziale complessivo di sorpresa (e rabbia). Non cambierà.
Erickson,

4
Generalmente, gli unici pacchetti Java JRE che vedo estesi provengono da Swing. Di solito, l'estensione di altre classi come java.io.File è una cattiva idea, in quanto ha la possibilità di far sì che le cose agiscano in modo imprevisto.
Eddie,

1

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

0

Mentre i file possono essere facilmente eliminati utilizzando file.delete (), le directory devono essere vuote per essere eliminate. Usa la ricorsione per farlo facilmente. Per esempio:

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

0

ho codificato questa routine che ha 3 criteri di sicurezza per un uso più sicuro.

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

0

Bene, facciamo un esempio,

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

Per ulteriori informazioni consultare le risorse di seguito

Elimina directory


0

rm -rfera molto più performante di FileUtils.deleteDirectory.

Dopo un ampio benchmarking, abbiamo scoperto che l'utilizzo è rm -rfstato più volte più veloce dell'utilizzo FileUtils.deleteDirectory.

Ovviamente, se hai una directory piccola o semplice, non importa, ma nel nostro caso avevamo più gigabyte e sottodirectory profondamente annidate dove ci sarebbero voluti più di 10 minuti FileUtils.deleteDirectorye solo 1 minuto con rm -rf.

Ecco la nostra approssimativa implementazione Java per farlo:

// 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 la pena provare se hai a che fare con directory grandi o complesse.


Funziona su piattaforme incrociate ??
OneCricketeer

@ cricket_007 Quali piattaforme?
Joshua Pinter

Finestre? OpenWrt? BSD?
OneCricketeer

1
@ cricket_007 Sicuramente non Windows. Questo è stato testato e utilizzato su Android e macOS.
Joshua Pinter

0

Guava fornisce un one-liner:MoreFiles.deleteRecursively() .

A differenza di molti degli esempi condivisi, tiene conto dei collegamenti simbolici e non (per impostazione predefinita) non eliminerà i file al di fuori del percorso fornito.

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.