Supprimer un répertoire de manière récursive en Java

Supprimer un répertoire de manière récursive en Java

1. introduction

Dans cet article, nous allons illustrer comment supprimer un répertoire de manière récursive en Java brut. Nous examinerons également quelques alternatives pour supprimer des répertoires à l'aide de bibliothèques externes.

2. Suppression récursive d'un répertoire

Java a la possibilité de supprimer un répertoire. Cependant, cela nécessite que le répertoire soit vide. Nous devons donc utiliser la récursivité pour supprimer un répertoire particulier non vide:

  1. Obtenir tout le contenu du répertoire à supprimer

  2. Supprimer tous les enfants qui ne sont pas un répertoire (quitter la récursion)

  3. Pour chaque sous-répertoire du répertoire en cours, commencez par l'étape 1 (étape récursive)

  4. Supprimer le répertoire

Implémentons cet algorithme simple:

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

Cette méthode peut être testée à l'aide d'un cas de test simple:

@Test
public void givenDirectory_whenDeletedWithRecursion_thenIsGone()
  throws IOException {

    Path pathToBeDeleted = TEMP_DIRECTORY.resolve(DIRECTORY_NAME);

    boolean result = deleteDirectory(pathToBeDeleted.toFile());

    assertTrue(result);
    assertFalse(
      "Directory still exists",
      Files.exists(pathToBeDeleted));
}

La méthode@Before de notre classe de test crée une arborescence de répertoires avec des sous-répertoires et des fichiers à l'emplacementpathToBeDeleted et la méthode@After nettoie le répertoire si nécessaire.

Ensuite, voyons comment nous pouvons réaliser la suppression en utilisant deux des bibliothèques les plus couramment utilisées -commons-io d'Apache etspring-core. de Spring Framework Ces deux bibliothèques nous permettent de supprimer les répertoires en utilisant une seule ligne du code.

3. Utilisation deFileUtils à partir decommons-io

Tout d'abord, nous devons ajouter la dépendancecommons-io au projet Maven:


    commons-io
    commons-io
    2.5

La dernière version de la dépendance peut être trouvéehere.

Maintenant, nous pouvons utiliserFileUtils pour effectuer toutes les opérations basées sur des fichiers, y comprisdeleteDirectory() avec une seule instruction:

FileUtils.deleteDirectory(file);

4. Utilisation deFileSystemUtils de Spring

Alternativement, nous pouvons ajouter la dépendance spring-core au projet Maven:


    org.springframework
    spring-core
    4.3.10.RELEASE

La dernière version de la dépendance peut être trouvéehere.

Nous pouvons utiliser la méthodedeleteRecursively() dansFileSystemUtils pour effectuer la suppression:

boolean result = FileSystemUtils.deleteRecursively(file);

Les dernières versions de Java offrent de nouvelles méthodes d'exécution des opérations IO décrites dans les sections suivantes.

5. Utilisation de NIO2 avec Java 7

Java 7 a introduit une toute nouvelle façon d'effectuer des opérations sur les fichiers à l'aide deFiles. Cela nous permet de parcourir une arborescence de répertoires et d'utiliser des rappels pour les actions à effectuer.

public void whenDeletedWithNIO2WalkFileTree_thenIsGone()
  throws IOException {

    Path pathToBeDeleted = TEMP_DIRECTORY.resolve(DIRECTORY_NAME);

    Files.walkFileTree(pathToBeDeleted,
      new SimpleFileVisitor() {
        @Override
        public FileVisitResult postVisitDirectory(
          Path dir, IOException exc) throws IOException {
            Files.delete(dir);
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFile(
          Path file, BasicFileAttributes attrs)
          throws IOException {
            Files.delete(file);
            return FileVisitResult.CONTINUE;
        }
    });

    assertFalse("Directory still exists",
      Files.exists(pathToBeDeleted));
}

La méthodeFiles.walkFileTree() parcourt une arborescence de fichiers et émet des événements. Nous devons spécifier des rappels pour ces événements. Donc, dans ce cas, nous définironsSimpleFileVisitor pour effectuer les actions suivantes pour les événements générés:

  1. Visiter un fichier - le supprimer

  2. Visiter un répertoire avant de traiter ses entrées - ne rien faire

  3. Visite d'un répertoire après le traitement de ses entrées - Supprimez le répertoire car toutes les entrées de ce répertoire auraient déjà été traitées (ou supprimées).

  4. Impossible de visiter un fichier - relancezIOException qui a causé l'échec

Veuillez vous référer àIntroduction to the Java NIO2 File API pour plus de détails sur les API NIO2 sur la gestion des opérations sur les fichiers.

6. Utilisation deNIO2 with Java 8

Depuis Java 8, Stream API offre un moyen encore plus efficace de supprimer un répertoire:

@Test
public void whenDeletedWithFilesWalk_thenIsGone()
  throws IOException {
    Path pathToBeDeleted = TEMP_DIRECTORY.resolve(DIRECTORY_NAME);

    Files.walk(pathToBeDeleted)
      .sorted(Comparator.reverseOrder())
      .map(Path::toFile)
      .forEach(File::delete);

    assertFalse("Directory still exists",
      Files.exists(pathToBeDeleted));
}

Ici,Files.walk() renvoie unStream dePath que nous trions dans l'ordre inverse. Cela place les chemins indiquant le contenu des répertoires avant les répertoires eux-mêmes. Ensuite, il mappePath àFile et supprime chaqueFile.

7. Conclusion

Dans ce rapide tutoriel, nous avons exploré différentes manières de supprimer un répertoire. Bien que nous ayons vu comment utiliser la récursivité pour supprimer, nous avons également examiné certaines bibliothèques, les événements NIO2 utilisant des événements et Java 8 Path Stream utilisant un paradigme de programmation fonctionnel.

Tous les codes source et scénarios de test de cet article sont disponiblesover on Github.