Supprimer les répertoires récursivement en Java


382

Existe-t-il un moyen de supprimer récursivement des répertoires entiers en Java?

Dans le cas normal, il est possible de supprimer un répertoire vide. Cependant, quand il s'agit de supprimer des répertoires entiers avec du contenu, ce n'est plus aussi simple que cela.

Comment supprimez-vous des répertoires entiers avec du contenu en Java?


4
File.delete () devrait simplement retourner false lors de son appel avec un répertoire non vide.
Ben S

Si vous utilisez Java 8, consultez la réponse de @ RoK.
Robin

Réponses:


462

Vous devriez vérifier le commun-io d'Apache . Il a une classe FileUtils qui fera ce que vous voulez.

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

3
Cette fonction encapsule probablement le code fourni par erickson dans sa réponse.
paweloque

14
C'est un peu plus approfondi. Il gère correctement des choses comme les liens symboliques sous Linux / Unix. svn.apache.org/viewvc/commons/proper/io/trunk/src/java/org/…
Steve K



Pourquoi ajouter une autre dépendance lorsque Java a une fonctionnalité prête à l'emploi? Voir la réponse de RoK sur cette page, ou stackoverflow.com/questions/35988192/…
foo

190

Avec Java 7, nous pouvons enfin le faire avec une détection fiable des liens symboliques. (Je ne considère pas que commons-io d'Apache ait une détection de lien symbolique fiable pour le moment, car il ne gère pas les liens sur Windows créés avec mklink.)

Par souci d'histoire, voici une réponse pré-Java 7, qui suit les liens symboliques.

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 () n'a pas cette fonctionnalité.
Ben S

14
@Erickson: FileNotFoundException n'est-il pas une mauvaise exception pour un échec de suppression? Si le fichier n'est vraiment plus là, il doit déjà avoir été supprimé, ce qui signifie que, sémantiquement, la suppression n'a pas échoué - il n'avait rien à faire. Et s'il a échoué pour une autre raison, ce n'est pas parce que le fichier n'a pas été trouvé.
Lawrence Dol

46
Soyez très prudent . Cela va déréférencer les liens symboliques. Si vous êtes sur Linux par exemple, et que vous avez un dossier fooavec un lien foo/linktel que link->/, l'appel delete(new File(foo)) supprimera autant de votre système de fichiers que votre utilisateur est autorisé à le faire !!
Miquel

4
@Miquel Cela n'a pas de sens - Pourquoi voudrions-nous faire attention? Le but du code fourni est sûrement de supprimer un répertoire entier, ce qu'il semble faire. Je ne comprends pas quel est le danger ici.
Joehot200

12
@ Joehot200 vous avez raison, appeler la suppression sur un lien symbolique de répertoire ne supprimera pas le répertoire, juste le lien symbolique lui-même. La suppression du répertoire nécessiterait en fait de suivre explicitement le lien symbolique à l'aide de ReadSymbolicLink . Ma faute! Bien repéré
Miquel

148

Dans Java 7+, vous pouvez utiliser la Filesclasse. Le code est très simple:

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
Cette solution semble très élégante et ne contient aucune logique de traversée de répertoire!
Zero3

1
"Pour trouver une plongée perle au fond de l'océan.". C'est de loin la meilleure solution que j'ai trouvée. J'ai dû plonger profondément pour le trouver. Brillant!
Basil Musa

20
"Le code n'est" PAS "très simple" pour supprimer simplement un répertoire :-) Mais bon, c'est la meilleure solution en java pur je pense.
Mat

1
Veuillez noter que la surcharge walkFileTree utilisée ici " ne suit pas les liens symboliques ". (Javadoc: docs.oracle.com/javase/7/docs/api/java/nio/file/… )
Stephan

1
Vous devriez probablement appeler super.postVisitDirectory(dir, exc);votre postVisitDirectoryméthode pour exploser si la marche ne peut pas lister un répertoire.
Tom Anderson

68

Solution à une ligne (Java8) pour supprimer tous les fichiers et répertoires de manière récursive, y compris le répertoire de départ:

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

Nous utilisons un comparateur pour l'ordre inversé, sinon File :: delete ne pourra pas supprimer le répertoire éventuellement non vide. Donc, si vous souhaitez conserver les répertoires et supprimer uniquement les fichiers, supprimez simplement le comparateur dans sorted () ou supprimez complètement le tri et ajoutez un filtre de fichiers:

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

1
Vous devez changer le tri dans le premier en .sorted (Comparator :: reverseOrder) pour supprimer tous les répertoires. Sinon, le répertoire parent est ordonné avant l'enfant et ne sera donc pas supprimé car il n'est pas vide. Excellente réponse pour ceux qui utilisent Java 8!
Robin

1
La bonne façon est que .sorted(Comparator.reverseOrder())la suggestion Comparator::reverseOrderne fonctionne pas . Voir: stackoverflow.com/questions/43036611/…
user1156544

4
Robin, fais attention au signe moins dans "-o1.compareTo (o2)". C'est la même chose que .sorted (Comparator.reverseOrder)
RoK

Files.walk est-il séquentiel? Ou est-ce que cette réponse nécessite forEachOrdered au lieu de forEach pour éviter d'essayer de supprimer des répertoires non vides?
Silwing

Utilisez simplement:, en .sorted((f1, f2) -> f2.compareTo(f1))comparant f2avec f1au lieu de f1avec f2.
Beto Neto

67

Java 7 a ajouté la prise en charge des répertoires de marche avec la gestion des liens symboliques:

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

Je l'utilise comme solution de rechange aux méthodes spécifiques à la plate-forme (dans ce code non testé ):

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 est de Apache Commons Lang . Les processus sont privés mais son comportement devrait être évident.)


Je trouve un problème avec Files.walkFileTree - il est insuffisant pour implémenter une version de suppression récursive où vous continuez à supprimer des fichiers jusqu'à ce que vous manquiez d'options. Il convient à une version à échec rapide, mais ce n'est pas toujours ce que vous voulez (par exemple, si vous nettoyez des fichiers temporaires, vous voulez les supprimer maintenant, pas à l'échec rapide.)
Trejkaz

Je ne vois pas pourquoi c'est vrai. Vous pouvez gérer les erreurs comme vous le souhaitez - vous n'êtes pas obligé d'échouer rapidement. Le seul problème que je pouvais prévoir est qu'il pourrait ne pas gérer les nouveaux fichiers créés pendant la marche du répertoire actuel, mais c'est une situation unique mieux adaptée à une solution personnalisée.
Trevor Robinson

1
Si vous supprimez l'erreur de visitFile et appelez walkFileTree sur un seul fichier qui échoue, vous n'obtenez aucune erreur (donc visitFile doit propager toute erreur qui se produit.) Si vous supprimez un répertoire et ne supprimez pas un fichier, le seul rappel appelé est postVisitDirectory. c'est-à-dire qu'il ne visite pas les autres fichiers du répertoire si vous obtenez une erreur lors de la visite d'un fichier. Voilà ce que je veux dire. Je suis sûr qu'il existe probablement un moyen de contourner cela, mais au moment où nous en sommes arrivés à ce point, nous avions déjà écrit plus de code qu'une routine de suppression récursive traditionnelle, nous avons donc décidé de ne pas l'utiliser.
Trejkaz

Merci pour votre 1er code, il m'a été utile, mais j'ai dû le changer, car il ne complétait pas un simple deltree: j'ai dû ignorer l'exception dans "postVisitDirectory" et renvoyer CONTINUER car l'arborescence simple suivante ne pouvait pas complètement être supprimé: un répertoire dans lequel il y avait un autre répertoire à l'intérieur duquel se trouvait un fichier. Le tout aussi simple / normal que possible, sous Windows.
président de Dreamspace,

Tout a commencé à partir d'une exception java.nio.file.DirectoryNotEmptyException que j'ai reçue. J'ai découvert le cas où visitFileFailed est utilisé. Si votre structure de répertoire a un lien de type jonction dans Windows. Cela peut vous causer 2 problèmes: *) Files.walkFileTree suit le lien dans la jonction et supprime tout ce qui s'y trouve. *) Si le répertoire cible de la jonction est déjà supprimé, l'analyse du lien par Files.walkFileTree échoue avec NoSuchFileException qui est intercepté dans visitFileFailed.
Andres Luuk

34

Je viens de voir que ma solution est plus ou moins la même que celle d'Erickson, juste emballée comme une méthode statique. Déposez cela quelque part, c'est beaucoup plus léger que d'installer tout Apache Commons pour quelque chose qui (comme vous pouvez le voir) est assez simple.

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

Une solution avec une pile et sans méthodes récursives:

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 pour l'utilisation d'une pile. Cela fonctionnera avec les répertoires qui contiennent des niveaux profonds de sous-répertoires imbriqués tandis que les autres approches basées sur la pile échoueront.
Nathan Osman

4
Étant donné que vous n'avez généralement pas de problèmes pour imbriquer quelques centaines d'appels de méthode, je pense que vous risquez de rencontrer des restrictions de système de fichiers beaucoup plus tôt.
Bombe

2
Soyez prudent avec les list*méthodes de classe java.io.File. À partir des Javadocs: "Renvoie null si ce chemin d'accès abstrait ne désigne pas un répertoire, ou si une erreur d'E / S se produit." Donc: if (currList.length > 0) {devientif (null != currList && currList.length > 0) {
kevinarpe

1
J'utilise un ArrayDeque au lieu d'une pile qui est légèrement plus rapide. (non synchronisé)
Wytze


15

La goyave avait Files.deleteRecursively(File)soutenu jusqu'à la goyave 9 .

Depuis Goyave 10 :

Obsolète. Cette méthode souffre d'une mauvaise détection des liens symboliques et des conditions de concurrence. Cette fonctionnalité ne peut être prise en charge de manière appropriée qu'en utilisant une commande du système d'exploitation telle que rm -rfou del /s. Cette méthode doit être supprimée de Guava dans la version 11.0 de Guava.

Par conséquent, il n'y a pas une telle méthode dans Guava 11 .


6
Dommage. Décortiquer semble un peu grossier et non portable. Si la version Apache commons fonctionne correctement, il n'est probablement pas impossible de l'implémenter.
Andrew McKinlay

6
@andrew L'implémentation d'Apache Commons devrait avoir des problèmes similaires à ceux qui provoquent la suppression de l'implémentation par Guava, voir code.google.com/p/guava-libraries/issues/detail?id=365
orip

La version d'apache commons détecte les liens symboliques et ne traverse simplement pas les enfants du fichier.
Ajax

5
Guava 21.0 l'a ajouté en tant que 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 si vous souhaitez gérer IOException:

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

2
Cela m'a aidé à trouver une version Scala:Files.walk(path).iterator().toSeq.reverse.foreach(Files.delete)
James Ward

Le tri est-il vraiment nécessaire? La walkméthode garantit déjà une traversée en profondeur.
VGR

Le comparateur peut être recyclé de Collections.reverseOrder()sorte que votre code for (Path p : Files.walk(directoryToDelete).sorted(reverseOrder()).toArray(Path[]::new))suppose qu'il a été importé statiquement.
namero999

@ namero999 Voulez-vous dire Comparator.reverseOrder? Files.walk(dir) .sorted(Comparator.reverseOrder()) .toArray(Path[]::new))
Jeff

@Jeff est sûr que vous avez raison, la plupart y sont allés de mémoire :)
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
Version améliorée avec valeur de retour booléenne et sans duplication: 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();
    }
}

Beau code, mais il y a un bug, une fois corrigé, cela fonctionne. La ligne f.delete()sous deleteDirectory(f)lèvera NoSuchFileException parce que deleteDirectory(f)déjà supprimer ce fichier. Chaque répertoire deviendra un chemin lorsqu'il sera transmis deleteDirectory(f)et supprimé par path.delete(). Par conséquent, nous n'avons pas besoin f.delete()dans la if f.isDerectorysection. Donc, supprimez simplement f.delete();sous deleteDirectory (f) et cela fonctionnera.
Trieu Nguyen

5

Deux façons d'échouer avec les liens symboliques et le code ci-dessus ... et je ne connais pas la solution.

Voie # 1

Exécutez ceci pour créer un test:

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

Ici, vous voyez votre fichier de test et votre répertoire de test:

$ ls testfile dirtodelete
testfile

dirtodelete:
linktodelete

Exécutez ensuite votre commons-io deleteDirectory (). Il se bloque en disant que le fichier est introuvable. Je ne sais pas ce que font les autres exemples ici. La commande Linux rm supprimerait simplement le lien, et rm -r sur le répertoire le ferait également.

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

Voie # 2

Exécutez ceci pour créer un test:

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

Ici, vous voyez votre fichier de test et votre répertoire de test:

$ ls dirtodelete testdir
dirtodelete:
dirlinktodelete

testdir:
testfile

Ensuite, exécutez votre commons-io deleteDirectory () ou l'exemple de code que les gens ont publié. Il supprime non seulement le répertoire, mais votre fichier de test qui se trouve en dehors du répertoire en cours de suppression. (Il déréférence implicitement le répertoire et supprime le contenu). rm -r supprimerait uniquement le lien. Vous devez utiliser quelque chose comme ceci, supprimez les fichiers déréférencés: "find -L dirtodelete -type f -exec rm {} \;".

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

4

Vous pouvez utiliser:

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

Supprime un fichier, sans jamais lancer d'exception. Si le fichier est un répertoire, supprimez-le ainsi que tous les sous-répertoires. La différence entre File.delete () et cette méthode est la suivante: Un répertoire à supprimer ne doit pas être vide. Aucune exception n'est levée lorsqu'un fichier ou un répertoire ne peut pas être supprimé.


4

Une solution optimale qui gère les exceptions de manière cohérente avec l'approche qu'une exception levée à partir d'une méthode doit toujours décrire ce que cette méthode essayait (et a échoué) de faire:

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

Dans les projets hérités, je dois créer du code Java natif. Je crée ce code similaire au code Paulitex. Regarde ça:

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

Et le test unitaire:

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

Le code ci-dessous supprime récursivement tout le contenu d'un dossier donné.

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

2

Voici une méthode principale de bare bones qui accepte un argument de ligne de commande, vous devrez peut-être ajouter votre propre vérification d'erreur ou l'adapter à votre convenance.

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

J'espère que ça aide!


1

Peut-être qu'une solution à ce problème pourrait être de réimplémenter la méthode de suppression de la classe File en utilisant le code de la réponse d'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
Je pense qu'il est implémenté car il imite le comportement de la plupart des utilitaires de shell de commande comme "rm", "rmdir" et "del". Parmi les deux alternatives, la mise en œuvre actuelle minimise définitivement le potentiel global de surprise (et de colère). Ça ne va pas changer.
erickson

4
Généralement, les seuls packages Java JRE étendus proviennent de Swing. Habituellement, l'extension d'autres classes telles que java.io.File est une mauvaise idée, car elle a la possibilité de faire en sorte que les choses agissent de manière inattendue.
Eddie

1

Sans Commons IO et <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

Alors que les fichiers peuvent facilement être supprimés à l'aide de file.delete (), les répertoires doivent être vides pour être supprimés. Utilisez la récursivité pour le faire facilement. Par exemple:

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

J'ai codé cette routine qui a 3 critères de sécurité pour une utilisation plus sûre.

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

Eh bien, supposons un exemple,

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

Pour plus d'informations, reportez-vous aux ressources ci-dessous

Supprimer le répertoire


0

rm -rfétait beaucoup plus performant que FileUtils.deleteDirectory.

Après une analyse comparative approfondie, nous avons constaté que l'utilisation rm -rfétait plusieurs fois plus rapide que l'utilisation FileUtils.deleteDirectory.

Bien sûr, si vous avez un répertoire petit ou simple, cela n'aura pas d'importance, mais dans notre cas, nous avions plusieurs gigaoctets et des sous-répertoires profondément imbriqués où cela prendrait plus de 10 minutes avec FileUtils.deleteDirectoryet seulement 1 minute avec rm -rf.

Voici notre implémentation Java approximative pour ce faire:

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

}

Cela vaut la peine d'essayer si vous avez affaire à des répertoires volumineux ou complexes.


Cela fonctionne-cross-plateforme ??
OneCricketeer

@ cricket_007 Quelles plateformes?
Joshua Pinter

Les fenêtres? OpenWrt? BSD?
OneCricketeer

1
@ cricket_007 Certainement pas Windows. Cela a été testé et utilisé sur Android et macOS.
Joshua Pinter

0

Guava fournit une seule ligne: MoreFiles.deleteRecursively().

Contrairement à de nombreux exemples partagés, il prend en compte les liens symboliques et ne supprime pas (par défaut) les fichiers en dehors du chemin fourni.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.