Удалить каталог рекурсивно в Java

Удалить каталог рекурсивно в Java

1. Вступление

В этой статье мы покажем, как рекурсивно удалить каталог на простом языке Java. Мы также рассмотрим некоторые альтернативы для удаления каталогов с помощью внешних библиотек.

2. Рекурсивное удаление каталога

У Java есть возможность удалить каталог. Однако для этого требуется, чтобы каталог был пустым. Итак, нам нужно использовать рекурсию для удаления определенного непустого каталога:

  1. Получить все содержимое каталога для удаления

  2. Удалить все дочерние элементы, которые не являются каталогом (выход из рекурсии)

  3. Для каждого подкаталога текущего каталога начните с шага 1 (рекурсивный шаг)

  4. Удалить каталог

Давайте реализуем этот простой алгоритм:

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

Этот метод может быть протестирован с использованием простого теста:

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

Метод@Before нашего тестового класса создает дерево каталогов с подкаталогами и файлами в местоположенииpathToBeDeleted, а метод@After при необходимости очищает каталог.

Затем давайте посмотрим, как мы можем добиться удаления с помощью двух наиболее часто используемых библиотек - Apachecommons-io и Spring Frameworkspring-core.. Обе эти библиотеки позволяют нам удалять каталоги, используя всего одну строку. кода.

3. ИспользованиеFileUtils изcommons-io

Во-первых, нам нужно добавить зависимостьcommons-io в проект Maven:


    commons-io
    commons-io
    2.5

Последнюю версию зависимости можно найтиhere.

Теперь мы можем использоватьFileUtils для выполнения любых файловых операций, включаяdeleteDirectory(), с помощью всего одного оператора:

FileUtils.deleteDirectory(file);

4. ИспользованиеFileSystemUtils из Spring

В качестве альтернативы мы можем добавить зависимость spring-core в проект Maven:


    org.springframework
    spring-core
    4.3.10.RELEASE

Последнюю версию зависимости можно найтиhere.

Мы можем использовать методdeleteRecursively() вFileSystemUtils для выполнения удаления:

boolean result = FileSystemUtils.deleteRecursively(file);

Недавние выпуски Java предлагают более новые способы выполнения таких операций ввода-вывода, описанные в следующих разделах.

5. Использование NIO2 с Java 7

В Java 7 был представлен совершенно новый способ выполнения файловых операций с использованиемFiles. Это позволяет нам обходить дерево каталогов и использовать обратные вызовы для выполнения действий.

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

МетодFiles.walkFileTree() просматривает дерево файлов и генерирует события. Нам нужно указать обратные вызовы для этих событий. Итак, в этом случае мы определимSimpleFileVisitor для выполнения следующих действий для сгенерированных событий:

  1. Посещение файла - удалить его

  2. Посещение каталога перед обработкой его записей - ничего не делать

  3. Посещение каталога после обработки его записей - удалите каталог, поскольку все записи в этом каталоге уже были бы обработаны (или удалены)

  4. Невозможно посетить файл - повторно вызовитеIOException, вызвавшее сбой

Пожалуйста, обратитесь кIntroduction to the Java NIO2 File API для получения дополнительных сведений об API NIO2 по обработке файловых операций.

6. ИспользуяNIO2 with Java 8

Начиная с Java 8, Stream API предлагает еще лучший способ удаления каталога:

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

ЗдесьFiles.walk() возвращаетStream изPath, которые мы сортируем в обратном порядке. Это помещает пути, обозначающие содержимое каталогов, перед самими каталогами. После этого он отображаетPath вFile и удаляет каждыйFile.

7. Заключение

В этом кратком руководстве мы рассмотрели различные способы удаления каталога. Хотя мы увидели, как использовать рекурсию для удаления, мы также рассмотрели некоторые библиотеки, события, использующие NIO2, и Java 8 Path Stream, использующие парадигму функционального программирования.

Весь исходный код и тестовые примеры для этой статьи доступныover on Github.