私は現在、ディレクトリを再帰的に削除しようとしています...奇妙なことに、アドホック内部クラスを使用して、次の構成が見つかりました訪問者パターン...
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
APIが非常に煩雑で定型的なものを削除することを考えると、恐ろしく不器用で冗長に感じます...
ディレクトリを強制的に再帰的に削除する短い方法はありますか?
私は純粋なネイティブJava 1.8メソッドを探しているので、外部ライブラリにリンクしないでください...
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
をFile
にマップします.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
は削除されません。
注:コードのコピーと貼り付けは、その機能を理解せずに使用しないでください。
次のソリューションでは、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);
}
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;
}
});
プロジェクトの一部として既にSpring Coreを使用している場合、簡単な方法があります。
FileSystemUtils.deleteRecursively(file);
Files.walk(pathToBeDeleted).sorted(Comparator.reverseOrder()).forEach(Files::delete);
「ファイルシステムリソースのタイムリーな廃棄が必要な場合」ストリームを閉じるには、「リソースで試す」パターンが必要になります。
また、おそらく歓迎されないコメントですが、ライブラリを使用する方がずっときれいで読みやすくなります。共有関数のコードでは、多くのスペースを占有しません。あなたのコードを見るすべての人は、このコードが適切な削除を行うことを検証しなければならず、それは決して明らかではありません。
FileUtils.deleteDirectory
from Apache Commons IO ディレクトリを再帰的に削除します。
例:
Path pathToBeDeleted = TEMP_DIRECTORY.resolve(DIRECTORY_NAME);
boolean result = FileUtils.deleteDirectory(pathToBeDeleted.toFile());
詳細については、「 Javaでディレクトリを再帰的に削除する 」を参照してください。