2016年7月6日水曜日

Files.walk() や Files.find() の困ったところ。 Files.walkFileTree() のススメ

Java の java.nio.file には java.nio.file.Files というとっても便利そうな static メソッドが集まったクラスがあります。
その中でも walk() や find() は、とあるディレクトリ配下を一気に収集して Stream として返してくれる、というとっても便利そうなメソッドなのですが、
なんとも悲しい落とし穴があります。

それは途中で Exception が発生した場合にはそこで終了してしまい、エラーハンドリングが出来ないというものです。
例えば、
try(Stream<Path> stp = Files.walk(Paths.get(”c:\\Windows”))){
    stp.forEach(System.out::println); }
のように c:\\Windows 配下のような権限不可で読めないファイル・ディレクトリの宝庫のところを対象として walk() すると、どこかで java.nio.file.AccessDeniedException とかが起きて walk 処理が止まってしまいます。
そういうところは飛ばして続けるという選択肢がありません。
これは Files.Find() でも同じです。

この点については、このページで議論されているように、FileVisitOption.IGNORE_ON_IOEXCEPTION なんてのが指定できると良いのにと思います。

ともかく、現状、こういう権限不可で読めない状況に対処して処理を続けたい場合には、
Files.walkFileTree() を使い visitFileFailed() でエラーハンドリングをするという対処方法になるようです。
(walk(), find() 相当の収集処理は visitFile() で自力で実装する)

で実装例がありますが、ポイントのところだけ抜き出すと
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
    @Override
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
        System.out.printf("Visiting file %s\n", file);
        /* ここで正常ケースの file について、リスト化していくなり、何か処理するなりを実装 */
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult visitFileFailed(Path file, IOException e) throws IOException {
        System.err.printf("Visiting failed for %s\n", file);
        /* アクセス不可なファイルは無視する */
        return FileVisitResult.SKIP_SUBTREE;
    }
});
といった感じになります。

0 件のコメント:

コメントを投稿