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
при необходимости очищает каталог.
Далее давайте посмотрим, как мы можем добиться удаления, используя две наиболее часто используемые библиотеки — Apache commons-io
и spring-core Spring Framework.
Обе эти библиотеки позволяют нам удалять каталоги, используя всего одну строку кода.
3. Использование FileUtils
из commons-io
Во- первых, нам нужно добавить зависимость commons-io
в проект Maven:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
Последнюю версию зависимости можно найти здесь .
Теперь мы можем использовать FileUtils
для выполнения любых операций с файлами, включая deleteDirectory()
, всего одним оператором:
FileUtils.deleteDirectory(file);
4. Использование FileSystemUtils
из Spring
В качестве альтернативы мы можем добавить зависимость s pring-core
к проекту Maven:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.10.RELEASE</version>
</dependency>
Последнюю версию зависимости можно найти здесь.
Мы можем использовать метод 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<Path>() {
@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
, вызвавшее сбой.
Пожалуйста, обратитесь к Введение в файловый API Java NIO2 для получения более подробной информации об API NIO2 для обработки файловых операций.
6. Использование NIO2 с 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()
возвращает поток
пути , который мы сортируем в обратном порядке .
Это помещает пути, обозначающие содержимое каталогов, перед самими каталогами. После этого он сопоставляет путь
к файлу
и удаляет каждый файл.
7. Заключение
В этом кратком руководстве мы рассмотрели различные способы удаления каталога. Пока мы видели, как использовать рекурсию для удаления, мы также рассмотрели некоторые библиотеки, NIO2, использующие события, и Java 8 Path Stream, использующий парадигму функционального программирования.
Весь исходный код и тестовые примеры для этой статьи доступны на GitHub .