Help us understand the problem. What is going on with this article?

Javaでrm -rfを実装する。

More than 1 year has passed since last update.

ディレクトリを再帰的に削除する処理、要するにrm -rfと同等の処理をJavaで実装する機会があったので、メモを残しておきます(´・ω・`) 今回の処理に限らず、ディレクトリを再帰的に処理したい場合はFiles.walkTreeが便利です。Files.walkTreeは第1引数に処理対象であるディレクトリのパス、第2引数にファイルやディレクトリを検出した際のふるまいを定義したFileVisitorを与えることで、再帰的な処理を簡単に実装することができます。

さてFileVisitorはインターフェイスで、4つのメソッドの実装を要求されるのですが、SimpleFileVisitorクラスを継承すれば、必要なメソッドをオーバライドするだけで、簡単に目的を達成することができます。たとえば、ディレクトリを再帰的にたどりながら、すべてのファイルとディレクトリを削除するFileVisitorは次のようにして作成することができます。

RemoveRecurseFileVisitor.java
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を作成します。

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

neko_the_shadow
IT業界の片隅でひっそり生きるシステムエンジニアです(´・ω・`)
https://nekotheshadow.github.io/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away