web-dev-qa-db-ja.com

Java.nio:最も簡潔な再帰ディレクトリ削除

私は現在、ディレクトリを再帰的に削除しようとしています...奇妙なことに、アドホック内部クラスを使用して、次の構成が見つかりました訪問者パターン...

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

ソース: here

これは、新しいnio AP​​Iが非常に煩雑で定型的なものを削除することを考えると、恐ろしく不器用で冗長に感じます...

ディレクトリを強制的に再帰的に削除する短い方法はありますか?

私は純粋なネイティブJava 1.8メソッドを探しているので、外部ライブラリにリンクしないでください...

37
fgysin

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-PathFileにマップします
  • .peek-処理されるエントリを表示するためだけにあります
  • .forEach-すべてのFileオブジェクトで.delete()メソッドを呼び出します

[〜#〜] edit [〜#〜]

以下にいくつかの図を示します。
ディレクトリ/data/to-deleteには、jdk1.8.0_73の解凍されたrt.jarと、 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

どちらのバージョンも、ファイル名を出力せずに実行されました。最も制限的な要因はドライブです。実装ではありません。

[〜#〜] edit [〜#〜]

オプション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は削除されません。

注:コードのコピーと貼り付けは、その機能を理解せずに使用しないでください。

104
SubOptimal

次のソリューションでは、Pathオブジェクトから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);
}
5
asmaier

NIOでJava 7のみを使用する必要がある場合

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
bigspawn

プロジェクトの一部として既にSpring Coreを使用している場合、簡単な方法があります。

FileSystemUtils.deleteRecursively(file);

ソース: http://www.baeldung.com/Java-delete-directory

3
justanother
Files.walk(pathToBeDeleted).sorted(Comparator.reverseOrder()).forEach(Files::delete);

「ファイルシステムリソースのタイムリーな廃棄が必要な場合」ストリームを閉じるには、「リソースで試す」パターンが必要になります。

また、おそらく歓迎されないコメントですが、ライブラリを使用する方がずっときれいで読みやすくなります。共有関数のコードでは、多くのスペースを占有しません。あなたのコードを見るすべての人は、このコードが適切な削除を行うことを検証しなければならず、それは決して明らかではありません。

1
user1122069

FileUtils.deleteDirectory from Apache Commons IO ディレクトリを再帰的に削除します。

例:

Path pathToBeDeleted = TEMP_DIRECTORY.resolve(DIRECTORY_NAME);

boolean result = FileUtils.deleteDirectory(pathToBeDeleted.toFile());

詳細については、「 Javaでディレクトリを再帰的に削除する 」を参照してください。

0