Java.nio: наиболее сжатый рекурсивный каталог delete
В настоящее время я пытаюсь рекурсивно удалить каталог... Как ни странно, самым коротким фрагментом кода, который я смог найти, является следующая конструкция, использующая внутренний класс ad-hoc и шаблон посетителя...
Path rootPath = Paths.get("data/to-delete");
try {
Files.walkFileTree(rootPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
System.out.println("delete file: " + file.toString());
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
Files.delete(dir);
System.out.println("delete dir: " + dir.toString());
return FileVisitResult.CONTINUE;
}
});
} catch(IOException e){
e.printStackTrace();
}
Источник: здесь
Это кажется ужасно неуклюжим и многословным, учитывая, что новые API nio
удаляют так много беспорядка и шаблона...
Есть ли какой-либо более короткий способ добиться принудительного рекурсивного каталога?
Я ищу чистые родные методы Java 1.8, поэтому, пожалуйста, не связывайтесь с внешними библиотеками...
Ответы
Ответ 1
Вы можете объединить NIO 2 и Stream API.
Path rootPath = Paths.get("/data/to-delete");
// before you copy and paste the snippet
// - read the post till the end
// - read the javadoc to understand what the code will do
//
// a) to follow softlinks (removes the linked file too) use
// Files.walk(rootPath, FileVisitOption.FOLLOW_LINKS)
//
// b) to not follow softlinks (removes only the softlink) use
// the snippet below
Files.walk(rootPath)
.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.peek(System.out::println)
.forEach(File::delete);
-
Files.walk
- вернуть все файлы/каталоги ниже rootPath
включая -
.sorted
- сортировка списка в обратном порядке, поэтому сам каталог идет после .sorted
подкаталогов и файлов. -
.map
- сопоставить Path
к File
-
.peek
- есть только, чтобы показать, какая запись обрабатывается -
.forEach
- вызывает метод .delete()
для каждого объекта File
РЕДАКТИРОВАТЬ
Вот некоторые цифры.
Каталог /data/to-delete
содержит распакованный rt.jar
из jdk1.8.0_73 и последнюю сборку activemq.
files: 36,427
dirs : 4,143
size : 514 MB
Раз в миллисекундах
int. SSD ext. USB3
NIO + Stream API 1,126 11,943
FileVisitor 1,362 13,561
Обе версии были выполнены без печати имен файлов. Наиболее ограничивающим фактором является драйв. Не реализация.
РЕДАКТИРОВАТЬ
Некоторая дополнительная информация о опции FileVisitOption.FOLLOW_LINKS
.
Предположим, следующая структура файлов и каталогов
/data/dont-delete/bar
/data/to-delete/foo
/data/to-delete/dont-delete -> ../dont-delete
С помощью
Files.walk(rootPath, FileVisitOption.FOLLOW_LINKS)
будет следовать символическим ссылкам, и файл /tmp/dont_delete/bar
будет также удален.
С помощью
Files.walk(rootPath)
не будет следовать символическим ссылкам, и файл /tmp/dont_delete/bar
не будет удален.
ПРИМЕЧАНИЕ. Никогда не используйте код для копирования и вставки, не понимая, что он делает.
Ответ 2
Следующее решение не нуждается в преобразовании из объектов Path to File:
Path rootPath = Paths.get("/data/to-delete");
final List<Path> pathsToDelete = Files.walk(rootPath).sorted(Comparator.reverseOrder()).collect(Collectors.toList());
for(Path path : pathsToDelete) {
Files.deleteIfExists(path);
}
Ответ 3
Если вы должны использовать только Java 7 с NIO
Path path = Paths.get("./target/logs");
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 postVisitDirectory(Path dir, IOException exc)
throws IOException {
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
Ответ 4
Если у вас уже есть Spring Core как часть вашего проекта, вот простой способ сделать это:
FileSystemUtils.deleteRecursively(file);
Источник: http://www.baeldung.com/java-delete-directory
Ответ 5
Files.walk(pathToBeDeleted).sorted(Comparator.reverseOrder()).forEach(Files::delete);
Вам понадобится шаблон "попробовать с ресурсами", чтобы закрыть поток, если "требуется своевременное удаление ресурсов файловой системы".
Также, возможно, нежелательный комментарий, но было бы намного чище и удобнее читать библиотеку. С кодом в разделяемой функции он не займет много места. Каждый, кто просматривает ваш код, должен подтвердить, что этот код правильно удаляется, и это ни в коем случае не очевидно.
Ответ 6
FileUtils.deleteDirectory
из Apache Commons IO рекурсивно удаляет каталог.
Пример:
Path pathToBeDeleted = TEMP_DIRECTORY.resolve(DIRECTORY_NAME);
boolean result = deleteDirectory(pathToBeDeleted.toFile());
Для получения дополнительной информации см. Удаление каталога рекурсивно в Java.