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プロジェクト]にあります。