NIO2 FileVisitorへのガイド

1概要

この記事では、NIO2の興味深い機能である FileVisitor インターフェースを探ります。

すべてのオペレーティングシステムおよびいくつかのサードパーティ製アプリケーションには、ユーザーが検索条件を定義するファイル検索機能があります。

このインタフェースは、そのような機能をJavaアプリケーションに実装するために必要なものです。すべての .mp3 ファイルを検索する、 .class ファイルを検索して削除する、または先月アクセスされていないすべてのファイルを検索する必要がある場合は、このインターフェースが必要です。

この機能を実装するために必要なすべてのクラスは、1つのパッケージにまとめられています。

import java.nio.file.** ;

2 FileVisitor のしくみ

FileVisitor インターフェイスを使用すると、ファイルツリーを任意の深さまでトラバースして、任意のブランチにあるファイルまたはディレクトリに対して任意の操作を実行できます。

FileVisitor インターフェースの典型的な実装は以下のようになります。

public class FileVisitorImpl implements FileVisitor<Path> {

    @Override
    public FileVisitResult preVisitDirectory(
      Path dir, BasicFileAttributes attrs) {
        return null;
    }

    @Override
    public FileVisitResult visitFile(
      Path file, BasicFileAttributes attrs) {
        return null;
    }

    @Override
    public FileVisitResult visitFileFailed(
      Path file, IOException exc) {
        return null;
    }

    @Override
    public FileVisitResult postVisitDirectory(
      Path dir, IOException exc) {
        return null;
    }
}

4つのインタフェースメソッドによって、トラバースプロセスの重要なポイントで必要な動作を指定できます。ディレクトリにアクセスする前、ファイルにアクセスするとき、または障害が発生したときとディレクトリにアクセスしたときです。

各段階での戻り値は FileVisitResult 型で、トラバースの流れを制御します。ファイルツリーをたどって特定のディレクトリを探し、見つかったときにプロセスを終了するか、特定のディレクトリまたはファイルをスキップしたい場合があります。

FileVisitResult は、 FileVisitor インターフェースメソッドの4つの可能な戻り値の列挙です。

  • FileVisitResult.CONTINUE - ファイルツリーのトラバーサルを示します。

それを返すメソッドが終了した後も継続するべきです FileVisitResult.TERMINATE ** - ファイルツリーの走査を停止し、no

他のディレクトリやファイルにアクセスする FileVisitResult.SKIP SUBTREE__ ** - この結果は、以下の場合にのみ意味があります。

他の場所では、 preVisitDirectory APIから返されます。 持続す​​る 。現在のディレクトリとそのすべてのディレクトリ サブディレクトリはスキップされるべきです FileVisitResult.SKIP SIBLINGS__ ** - トラバーサルを実行する必要があることを示します

現在のファイルまたはディレクトリの兄弟を訪問せずに続行します。

preVisitDirectory フェーズで呼び出された場合は、現在のディレクトリもスキップされ、 postVisitDirectory は呼び出されません。

最後に、おそらくユーザーが検索条件を定義した後にグラフィカルユーザーインターフェースから search ボタンをクリックしたときに、トラバースプロセスを起動する方法が必要です。これが最も簡単な部分です。

Files クラスの静的 walkFileTree APIを呼び出して、トラバーサルの開始点を表す Path クラスのインスタンスを渡し、次に FileVisitor のインスタンスを渡すだけです。

Path startingDir = Paths.get("pathToDir");
FileVisitorImpl visitor = new FileVisitorImpl();
Files.walkFileTree(startingDir, visitor);

3ファイル検索の例

このセクションでは、 FileVisitor インターフェイスを使用してファイル検索アプリケーションを実装します。ユーザーが拡張子付きの完全なファイル名と、検索する開始ディレクトリを指定できるようにします。

ファイルが見つかったら、成功メッセージを画面に表示し、ファイルが見つからずにファイルツリー全体を検索した場合は、適切な失敗メッセージも印刷します。

** 3.1. メインクラス

このクラスをファイル検索Example.javaと呼びます。

public class FileSearchExample implements FileVisitor<Path> {
    private String fileName;
    private Path startDir;

   //standard constructors
}

まだインターフェースメソッドを実装していません。検索するファイルの名前と検索を開始するパスをとるコンストラクタを作成したことに注意してください。ファイルが見つからなかったと結論付けるために、基本パスとして開始パスのみを使用します。

以下のサブセクションでは、各インターフェースメソッドを実装し、この特定のサンプルアプリケーションにおけるその役割について説明します。

3.2. preVisitDirectory API

preVisitDirectory APIを実装することから始めましょう。

@Override
public FileVisitResult preVisitDirectory(
  Path dir, BasicFileAttributes attrs) {
    return CONTINUE;
}

前述したように、このAPIはプロセスがツリー内の新しいディレクトリに遭遇するたびに呼び出されます。その戻り値は、私たちが決めたことに応じて次に何が起こるかを決定します。これが、特定のディレクトリをスキップしてそれらを検索サンプルスペースから除外するポイントです。

ディレクトリを区別せず、それらすべてを検索するだけで済みます。

3.3. visitFile API

次に、 visitFile APIを実装します。これが主な行動が起こるところです。このAPIはファイルが見つかるたびに呼び出されます。これを利用してファイル属性をチェックし、基準と比較して適切な結果を返します。

@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
    String fileName = file.getFileName().toString();
    if (FILE__NAME.equals(fileName)) {
        System.out.println("File found: " + file.toString());
        return TERMINATE;
    }
    return CONTINUE;
}

私たちの場合は、訪問しているファイルの名前だけを調べて、ユーザーが探しているファイルかどうかを確認します。名前が一致すれば、成功メッセージを表示してプロセスを終了します。しかし、ここでできることはたくさんあります。特に、

しかし、特に File Attributes セクションを読んだ後に、ここでできることはたくさんあります。作成日時、最終変更日時、最終アクセス日時、または attrs パラメーターで使用可能ないくつかの属性を確認して、それに応じて決定できます。

3.4. visitFileFailed API

次に、 visitFileFailed APIを実装します。このAPIは、特定のファイルがJVMにアクセスできない場合に呼び出されます。おそらくそれは別のアプリケーションによってロックされているか、あるいは単に許可の問題になる可能性があります。

@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
    System.out.println("Failed to access file: " + file.toString());
    return CONTINUE;
}

失敗メッセージをログに記録して、残りのディレクトリツリーをたどっていきます。グラフィカルアプリケーションでは、ダイアログボックスを使用するかどうかをユーザーに確認するか、メッセージをどこかに記録して後で使用するためにレポートを編集するかを選択できます。

3.5. postVisitDirectory API

最後に、 postVisitDirectory APIを実装します。このAPIは、ディレクトリが完全にトラバースされるたびに呼び出されます。

@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc){
    boolean finishedSearch = Files.isSameFile(dir, START__DIR);
    if (finishedSearch) {
        System.out.println("File:" + FILE__NAME + " not found");
        return TERMINATE;
    }
    return CONTINUE;
}

トラバースを開始したディレクトリがトラバースを開始したディレクトリかどうかを確認するために Files.isSameFile APIを使用します。戻り値が true の場合、それは検索が完了しファイルが見つからなかったことを意味します。そのため、失敗メッセージを出してプロセスを終了します。

ただし、戻り値が false の場合は、サブディレクトリをたどったところで、他のサブディレクトリでファイルが見つかる可能性がまだあります。それで我々は横断を続けます。

これで、 FileSearchExample アプリケーションを実行するためのメインメソッドを追加できます。

public static void main(String[]args) {
    Path startingDir = Paths.get("C:/Users/user/Desktop");
    String fileToSearch = "hibernate-guide.txt"
    FileSearchExample crawler = new FileSearchExample(
      fileToSearch, startingDir);
    Files.walkFileTree(startingDir, crawler);
}

startingDir 変数と fileToSearch 変数の値を変更することで、この例を試してみることができます。 fileToSearch startingDir またはそのサブディレクトリのいずれかに存在する場合は、成功メッセージが表示されます。それ以外の場合は失敗メッセージが表示されます。

4結論

この記事では、Java 7 NIO.2ファイルシステムAPIで使用可能な、あまり使用されていない機能、特に FileVisitor インターフェースについて説明しました。また、ファイル検索アプリケーションを作成してその機能を実証するための手順を順を追って説明しました。

この記事で使用されている例の完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/core-java-io[Githubプロジェクト]にあります。