SimpleFileVisitorとFiles#walkFileTreeによるディレクトリ(サブディレクトリ含む)の削除方法

これまで何度かにわたってJava7で追加になったIO関連の機能についてメモ的に残してきましたが、前回紹介したプログラムにディレクトリとファイルの削除を行う処理があったと思います。

Filesクラスのdeleteメソッドを実行すると引数で渡したPathオブジェクトが示すディレクトリやファイルを削除してくれるのですが、Pathがディレクトリの場合、サブディレクトリやファイルが存在すると削除することができません。

それらも含めて、ディレクトリを削除するにはどうするかというと、まずはSimpleFileVisitorというクラスを継承して削除処理を行うようなクラスを作成します。

次にFilesクラスのwalkFileTreeメソッドの引数に削除したいディレクトリのPathオブジェクトと、SimpleFileVisitorを継承して作成した削除用のVisitorクラスを渡して実行します。

import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;

public class Main {

    public static void main(String[] args) {
        prepare();
        final Path rootPath = FileSystems.getDefault().getPath("path_to_removed_dir");
        try {
            Files.walkFileTree(rootPath, new DeleteVisitor());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void prepare() {
        Path testDirPath = FileSystems.getDefault().getPath("path_to_dir_and_sub_dir");
        try {
            // サブディレクトリも含めたディレクトリ作成
            Files.createDirectories(testDirPath);
            if (Files.exists(testDirPath)) {
                System.out.println("The new directories were created.");
            } else {
                System.out.println("Failed creating the directory.");
                System.exit(1);
            }
            // ファイル作成
            Path newFilePath = FileSystems.getDefault().getPath(testDirPath.toString() + "/hoge.txt");
            Files.createFile(newFilePath);
            if (Files.exists(newFilePath)) {
                System.out.println("The new file was created.");
            } else {
                System.out.println("Failed creating the new file.");
                System.exit(1);
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
}
import java.io.IOException;
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 DeleteVisitor extends SimpleFileVisitor<Path> {

    @Override
    public FileVisitResult visitFile(Path path, BasicFileAttributes attributes) throws IOException {
        System.out.println("delete file : " + path.getFileName());
        Files.delete(path);
        return checkNotExist(path);
    }
    
    @Override
    public FileVisitResult postVisitDirectory(Path path, IOException exception) throws IOException {
        if (exception == null) {
            System.out.println("delete directory : " + path.getFileName());
            Files.delete(path);
            return checkNotExist(path);
        } else {
            throw exception;
        }
        
    }
    
    private static FileVisitResult checkNotExist(final Path path) throws IOException {
        if (!Files.exists(path)) {
            return FileVisitResult.CONTINUE;
        } else {
            throw new IOException();
        }
    }
}


Files#walkFileTreeメソッドはその名の通り第一引数のPathオブジェクトが示すディレクトリ内を走査し、ファイル/ディレクトリに到達すると第二引数で渡したDeleteVisitorのいずれかのメソッドを実行します。

第二引数で指定したDeleteVisitorクラスはSimpleFileVisitorを継承し、visitFileとpostVisitDirectoryメソッドをオーバーライドしています。

visitFileメソッドはファイルに到達したときに実行されるメソッドで、このサンプルではファイルの削除を行っています。

postVisitDirectoryメソッドはディレクトリに到達した後に実行される処理で、ここではIOExceptionがnullならばディレクトリの削除処理を行い、nullでなければ例外を再スローしています。

chechNotExistメソッドは削除確認メソッドです。対象のPathオブジェクトが存在しなければFileVisitResult.CONTINUEを返し、削除したはずのオブジェクトが存在する場合はIOExceptionをスローします。(これは独自メソッドです。)

visitFileメソッド、postVisitDirectorメソッドともにFileVisitResultを返す必要があります。ここでは処理が成功すればFileVisitResult.CONTINUEが戻り値となります。

CONTINUEは処理を継続することを意味します。すべてのディレクトリ走査が終了するとwalkFileTreeメソッドに渡したPathオブジェクトが示すディレクトリ(サブディレクトリ、ファイル含む)が削除されます。

SimpleFileVisitorクラスのメソッドはこれ以外にもたとえばディレクトリに到達した場合の処理などを行うメソッドがありオーバーライドして任意の処理を記載することが可能ですが、このクラスの説明については省略します。