ディレクトリを再帰的に削除する処理、要するにrm -rf
と同等の処理をJavaで実装する機会があったので、メモを残しておきます(´・ω・`) 今回の処理に限らず、ディレクトリを再帰的に処理したい場合はFiles.walkTree
が便利です。Files.walkTree
は第1引数に処理対象であるディレクトリのパス、第2引数にファイルやディレクトリを検出した際のふるまいを定義したFileVisitor
を与えることで、再帰的な処理を簡単に実装することができます。
さてFileVisitor
はインターフェイスで、4つのメソッドの実装を要求されるのですが、SimpleFileVisitor
クラスを継承すれば、必要なメソッドをオーバライドするだけで、簡単に目的を達成することができます。たとえば、ディレクトリを再帰的にたどりながら、すべてのファイルとディレクトリを削除するFileVisitor
は次のようにして作成することができます。
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
public class RemoveRecurseFileVisitor extends SimpleFileVisitor<Path> {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
return delete(file);
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
return delete(dir);
}
private FileVisitResult delete(Path path) {
try {
Files.deleteIfExists(path);
System.out.printf("removed '%s'%n", path);
return FileVisitResult.CONTINUE;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
では作成したコードを実際に動かしてみます。まずは以下に示す一連のコマンドを順番に実行します。
mkdir -p dir01/dir02/dir03
touch dir01/file1
touch dir01/dir02/file2
touch dir01/dir02/file3
touch dir01/dir02/dir03/file4
touch dir01/dir02/dir03/file5
touch dir01/dir02/dir03/file6
すると次のようなディレクトリ・ファイルが作成されるはずです。
$ find dir1/ -exec stat -c '%n (%F)' {} \;
dir1/ (directory)
dir1/dir2 (directory)
dir1/dir2/dir3 (directory)
dir1/dir2/dir3/txt4 (regular empty file)
dir1/dir2/dir3/txt5 (regular empty file)
dir1/dir2/dir3/txt6 (regular empty file)
dir1/dir2/txt2 (regular empty file)
dir1/dir2/txt3 (regular empty file)
dir1/txt1 (regular empty file)
ここでRemoveRecurseFileVisitor
を利用して、dir1
とその配下にあるファイルとディレクトリを削除するMain.java
を作成します。
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Main {
public static void main(String[] args) throws IOException {
var target = Paths.get("dir1");
Files.walkFileTree(target, new RemoveRecurseFileVisitor());
}
}
あとはこれをコンパイル&実行すると、まずは標準出力に削除ログが出力されることが確認できるはずです(´・ω・`)
removed 'dir1\dir2\dir3\txt4'
removed 'dir1\dir2\dir3\txt5'
removed 'dir1\dir2\dir3\txt6'
removed 'dir1\dir2\dir3'
removed 'dir1\dir2\txt2'
removed 'dir1\dir2\txt3'
removed 'dir1\dir2'
removed 'dir1\txt1'
removed 'dir1'
以下のようなコマンドで、ディレクトリdir1
とその配下すべてが削除されていることが確認できます。
$ ls -l dir1
ls: cannot access 'dir1': No such file or directory
参考: https://docs.oracle.com/javase/tutorial/essential/io/walk.html