Удалить каталог рекурсивно в Java
1. Вступление
В этой статье мы покажем, как рекурсивно удалить каталог на простом языке Java. Мы также рассмотрим некоторые альтернативы для удаления каталогов с помощью внешних библиотек.
2. Рекурсивное удаление каталога
У Java есть возможность удалить каталог. Однако для этого требуется, чтобы каталог был пустым. Итак, нам нужно использовать рекурсию для удаления определенного непустого каталога:
-
Получить все содержимое каталога для удаления
-
Удалить все дочерние элементы, которые не являются каталогом (выход из рекурсии)
-
Для каждого подкаталога текущего каталога начните с шага 1 (рекурсивный шаг)
-
Удалить каталог
Давайте реализуем этот простой алгоритм:
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 для выполнения следующих действий для сгенерированных событий:
-
Посещение файла - удалить его
-
Посещение каталога перед обработкой его записей - ничего не делать
-
Посещение каталога после обработки его записей - удалите каталог, поскольку все записи в этом каталоге уже были бы обработаны (или удалены)
-
Невозможно посетить файл - повторно вызовите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.