Ява.nio: самый краткий рекурсивный каталог удалить

в настоящее время я пытаюсь рекурсивно удалить каталог... Как ни странно, самый короткий фрагмент кода, который я смог найти, - это следующая конструкция, использующая специальный внутренний класс и шаблон Visitor...

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

источник: здесь

это чувствует себя ужасно неуклюжим и многословным, учитывая, что новый nio API удаляют так много беспорядка и шаблонности...

есть ли более короткий путь достижение принудительного рекурсивного удаления каталога?

Я ищу чистые собственные методы Java 1.8, поэтому, пожалуйста, не связывайтесь с внешними библиотеками...

5 ответов


вы можете объединить 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 - сортировка списка в обратном порядке, поэтому сам каталог поставляется после включения подкаталогов и файлов
  • .map - карты Path to 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 не будет удален.

Примечание: никогда не используйте код в качестве копирования и вставки без понимания что он делает.


следующее решение не требует преобразования из Path в File objects:

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

Если вы должны использовать только 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;
  }
});

Если у вас уже есть Spring Core как часть вашего проекта, вот простой способ сделать это:

FileSystemUtils.deleteRecursively(file);

Источник:http://www.baeldung.com/java-delete-directory


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

источник:http://www.baeldung.com/java-delete-directory (Используя NIO2 с Java 8).

также, вероятно, нежелательный комментарий, но было бы намного чище и читабельнее использовать библиотеку. С кодом в общей функции он не займет много места. Каждый человек, который смотрит на ваш код, должен проверить, что этот код делает правильное удаление, и это отнюдь не очевидно.