2016年11月30日水曜日

ディレクトリの監視(監視ディレクトリの登録方法)

みなさん。 こんばんは。

今日はディレクトリの監視について見ていきましょう。

ディレクトリの監視とは、指定したディレクトリに関する変更があるかどうかチェックする機能です。

標準では、ファイルやディレクトリの作成、削除、変更の監視を行うことができます。

既存のFileクラスでは、監視機能は提供されていませんでした。

このため、定期的にファイル一覧を取得するなどして監視を行う必要がありましたが、NIO.2を使用すれば簡単に監視を行うことができます。

ディレクトリの監視を行うのはWatchServiceインターフェースです。

これはFilesSystemクラスから取得します。

WatchServiceオブジェクトを取得するのはFileSystemクラスのnewWatchServiceメソッドです。

ファイルシステムがディレクトリの監視に対応していない場合、UnsupportedOperationException例外がスローされます。

ターゲットとなるディレクトリの監視を開始するには、Pathインターフェースのregisterメソッドを使用します。

registerメソッドの第1引数がWatchServiceオブジェクト、第2引数は可変長引数で、ここにイベントの種類を列挙します。

第2引数の型はWatchEvent.Kindインターフェースです。

しかし、実際に使用されるのはWatchService.Kindインターフェースを実装したStandardWatchEventKindsクラスになります。

StandartWatchEventKindsクラスには4種類の定数が定義されていますが、registerメソッドで使用できるのは以下の3種類です。


  • ENTRY_CREATE : ファイル/ディレクトリの作成
  • ENTRY_DELETE : ファイル/ディレクトリの削除
  • ENTRY_MODIFY : ファイル/ディレクトリの更新


なお、registerメソッドの第1引数にディレクトリではないPathオブジェクトを指定すると、NotDirectoryException例外がスローされます。

では実際に監視対象となるディレクトリの登録例を見てみましょう。

// WatchServiceオブジェクトの生成
WatchService watchService = FileSystems.getDefault().newWatchService();
// 監視の対象となるディレクトリ
Path target = Paths.get(targetDirectory);
// ディレクトリの監視を登録
target.register(watchService,
                    StandardWatchEventKinds.ENTRY_CREATE,
                    StandardWatchEventKinds.ENTRY_DELETE,
                    StandardWatchEventKinds.ENTRY_MODIFY);

上記のソースでは、デフォルトのファイルシステムを使用してWatchServiceオブジェクトを取得しています。

そして、ディレクトリに対して、ENTRY_CREATE、ENTRY_DELETE、ENTRY_MODIFYの3種類の監視イベントを登録しています。

ディレクトリ監視の登録をすると、ディレクトリの監視が開始されます。

ディレクトリの監視の登録が終わったので、実際にどのようにディレクトリの監視するのかは次回に記述していきます。

今日はこの辺にしておきましょう。

それではまた!
人気ブログランキングへ

2016年11月21日月曜日

ディレクトリのコピー

みなさん。 こんばんは。

前回はファイルツリーの走査のサンプルを見ましたが、今回はもう少し役に立つサンプルとしてディレクトリのコピーについて見てみましょう。

ディレクトリのコピーを行うには、次に示す手順で行います。

  1. ディレクトリをコピーする。このとき、ディレクトリに存在するファイル/ディレクトリはコピーされない。
  2. ディレクトリに存在するファイルをコピーする。
  3. サブディレクトリが存在したら、①に戻る。サブディレクトリがなくなるまで①と②を繰り返す。
ファイルツリーの走査を使用して、この手順を実現していきます。

①はpreVisitDirectoryメソッドで処理可能です。
次の②はvisitFileメソッドで実装できます。
③に関してはwalkFileTreeメソッドの内部で制御する処理なので、実装はありません。

ということは、preVisitDirectoryメソッドとvisitFileメソッドを実装したFileVisitorオブジェクトを生成すればよいことになります。

postVisitDirectoryメソッドなどは実装する必要がないため、ここではSimpleFileVisitorクラスの匿名クラスとして実装してみます。

// ディレクトリのコピー
// コピー元のディレクトリ
Path source = Paths.get(sourceDirectory);
// コピー先のディレクトリ
Path dest = Paths.get(destDirectory);
// ファイルツリーをたどって、ファイル/ディレクトリをコピーするFileVisitor
FileVisitor<Path> visitor = new SimpleFileVisitor<Path>() {
          @Override
          public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                    throws IOException {
                 // ディレクトリのコピー
                 Files.copy(dir, dest.resolve(dir), StandardCopyOption.COPY_ATTRIBUTES);
                 return FileVisitResult.CONTINUE;
          }
          @Override
          public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
                     throws IOException {
                  // ファイルをコピー
          Files.copy(file, dest.resolve(file), StandardCopyOption.COPY_ATTRIBUTES);
                  return FileVisitResult.CONTINUE;
          }
};

// ディレクトリのコピーを実行!!Files.walkFileTree(source, visitor);

上記のpreVisitDirectoryでは、ディレクトリのコピーをcopyメソッドを使用して行っています。

コピー先のディレクトリ名を解決するために使用しているのが、Pathインターフェースのresolveメソッドです。

resolveメソッドはディレクトリに対するコピーはディレクトリだけをコピーし、ディレクトリにあるファイルはコピーしません。

ファイルツリーに存在するファイルに到達するとvisitFileメソッドがコールされるので、このときにファイルのコピーを行います。

このときも、resolveメソッドを使用してファイル名の解決を行っています。

今回はファイルツリーの走査をしてディレクトリのコピーをするサンプルを記述しました。

では今日はこの辺で!

人気ブログランキングへ

2016年11月17日木曜日

ファイルツリーの走査例

みなさん。 こんばんは。

前回はファイルツリーの走査の概要について記述しました。

今回は実際の実装例について見ていきましょう。

まず、FileVisitorインターフェースの匿名クラスを示します。

それぞれのメソッドはすべて、第1引数の型はPathインターフェースになります。

preVisitDirectoryメソッドとvisitFileメソッドは、第2引数の型がBasicFileAttributesクラスになります。

postVisitDirectoryメソッドとvisitFileFailedメソッドの第2引数の型はIOException例外となり、

走査中に発生した例外が引数となります。ただし、走査が正常に行われた場合、

postVisitDirectoryメソッドの第2引数の値はnullになります。

すべてのメソッドの返り値の型はFileVisitResult列挙型です。

FileVisitResult列挙型は以下の4種類の値を取ります。


  • CONTINUE
  • SKIP_SIBLINGS
  • SKIP_SUBTREE
  • TERMINATE


走査を続けるのであればCONTINUEを返します。

SKIP_SUBLINGSはディレクトリに依存するそれ以降のファイル/ディレクトリの走査をスキップするために使用します。

同様にSKIP_SUBTREEもサブツリーの走査をスキップするために使用します。

最後のTERMINATEは走査を中止させます。

// ファイルツリーを走査するFileVisitor
FileVisitor<Path> visitor = new FileVisitor<Path>() {
@Override
public FileVisitResult preVisitDIrectory(Path dir, BasicFileAttributes attrs) {
         System.out.println("Pre visit Directory; " + dir);
         return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
         System.out.println("Visit File: " + file);
         return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
         System.out.println("Post Visit Directory: " + dir);
         return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
         System.out.println("Visit File Failed: " + file);
         return FileVisitResult.TERMINATE;
}
};
// ファイルツリーの走査実行
Path path = Paths.get("alpha");
Files.walkFileTree(path, visitor);

上記のソースでは、4種類のメソッドとともに第1引数を標準出力に出力する処理だけを行っています。

これで、どのメソッドがどの順番にコールされるかわかるはずです。

visitFileFailedメソッド以外のメソッドは正常に走査が行われているので、返り値としてCONTINUEを返しています。

visitFileFailedメソッドだけは、何らかの異常が発生したことを示しているので、走査を中止するためTERMINATEを返すようにしています。

Paths.getメソッドの引数に起点のディレクトリを指定し、FilesクラスのwalkFileTreeメソッドが実際にファイルツリーの走査を行います。

今回はFileVisitorインターフェースの匿名クラスを使用しましたが、空のメソッドが定義されている
SimpleFileVisitorクラスを使用して必要なメソッドだけオーバーライドすることもできます。

今回はコンソールに出力するだけでしたが、次回はもう少し役にたつ実装例を示していきたいと思います。

それでは今日はこの辺で!

人気ブログランキングへ

2016年11月15日火曜日

ファイルツリーの走査

みなさん。 お久しぶりです。

今日はファイルツリーの走査について見てみましょう。

Filesクラスのcopyメソッドを使用してディレクトリのコピーを行う場合、

ディレクトリに存在するファイルなどはコピーされません。

ディレクトリのすべてのファイル/ディレクトリのコピーを行うにはディレクトリの構造をたどり、

ファイルツリーの末端までファイルをコピーしていく必要があります。

しかし、いままでのFileクラスではファイルツリーをたどることはできるものの、

煩雑になりがちでした。

そこで、NIO2ではデザインパターンのVisitorパターンを利用して、

ファイルツリーを走査する機能が提供されました。

ここでは、Visitorパターンについての詳細については述べませんが、簡単に動作を説明しましょう。

Visitorは、指定されたディレクトリからファイルツリーをだどっていきます。

ファイルツリーのディレクトリ/ファイルに到達するとVisitorのコールバックメソッドがコールされます。

Visitorはファイルツリーの末端までたどっていくことで、ファイルツリーの存在するすべての

ディレクトリやファイルを走査することができます。

NIO2でVisitorとして使用されるのが、java.nio.file.FileVisitorインターフェースです。

FileVisitorインターフェースには以下の4種類のメソッドが定義されています。


  • previsitDirectoryメソッド

  • postVisitDirectoryメソッド

  • visitFileメソッド

  • visitFIleFailedメソッド


preVisitDirectoryメソッドはディレクトリに入ったときにコールされるメソッドです。

preVisitDirectoryメソッドがコールされた後、そのディレクトリに存在するファイルがあると

visitFileメソッドがコールされます。

そして、ディレクトリから抜けるとき、postVisitDirectoryメソッドがコールされます。

また、ファイルツリーの走査に失敗すると、visitFileFailedメソッドがコールされます。

文章では解りづらいので、次回はこれらの実装について見ていきます。

それでは今日はこの辺で!

人気ブログランキングへ

2016年11月3日木曜日

アトリビュートの設定

みなさん。 こんばんは。

今日はファイルのアトリビュートをまとめて設定してみましょう。

設定を行うインターフェース群は、すべて java.nio.file.attribute.AttributeView インターフェースの

継承関係にあります。

ファイルやディレクトリに対するアトリビュートを設定するために使用されるのがFileAttributeView

インターフェースです。

しかし、FileAttributeViewインターフェースにはメソッドが定義されていません。

実際には、用途ごとに定義されているFileAttributeViewインターフェースのサブインターフェースを

使用します。

BasicFileAttributeViewインターフェースはOSに依存しない共通のアトリビュートを設定するための

インターフェースです。

アトリビュートの取得に使用したBasicFileAttributesインターフェースに対応しており、

BasicFileAttributesインターフェースで取得できるアトリビュートを設定することができます。

そして、OSに依存したアトリビュートの設定を行うには、Windows用のDosFileAttributeView

インターフェース、POSIXに準拠したOS用のPosixFileAttributeViewインターフェースを使用します。

それぞれDosFileAttributesインターフェース、PosixFileAttributesインターフェースに対応してます。

PosixFileAttributeViewインターフェースはBasicFileAttributeViewインターフェースだけでなく、

FileOwnerAttributeViewインターフェースも継承しています。

FileOwnerAttributeViewインターフェースはオーナを設定するためのインターフェースです。

FileOwnerAttributeViewインターフェースのサブインターフェースはもう1つ、

AclFileAttributeViewインターフェースが提供されています。

インターフェース名のACLはAccess Control List (アクセス制御リスト)の略称です。

NIO.2のACLはRFC 3350: Network File System(NFS) version4 Protocol に基づいています。

これらのインターフェースのオブジェクトを取得するには、FilesクラスのgetFileAttributeView

メソッドを使用します。

getFileAttributeViewメソッドは、第1引数の型がPathインターフェース、

第2引数の型がClassクラス、第3引数は可変長引数でLinkOption列挙型になります。

取得したいインターフェースを第2引数に指定することで、オブジェクトを取得できます。

今回はDosFileAttributeViewインターフェースとPosixFileAttributeViewインターフェースの

オブジェクトを取得して、アトリビュートを設定してみます。

BasicFileAttributeViewインターフェースは最終更新日時、最終アクセス日、作成日時を設定する

setTimeメソッドを定義しています。

同様に、DosFileAttributeViewインターフェースはファイルをリードオンリーに設定する

setReadOnlyメソッド、隠しファイルに設定するsetHiddenメソッド、アーカイブファイルに設定する

setArchiveメソッド、そしてシステムファイルに設定するsetSystemメソッドなどを定義しています。

PosixFileAttributeViewインターフェースはパーミッションを設定するsetPermissionsメソッドと

グループを設定するsetGroupメソッドを定義しています。

また、PosixFileAttributeViewインターフェースのスーパーインターフェースである

FileOwnerAttributeViewインターフェースではオーナを設定するsetOwnerメソッドを定義してます。

では、まずWindowsで複数のアトリビュートをまとめて設定してみましょう。

// 対象となるパスPath path = Paths.get("var.txt");
// Windows用のDosFileAttributeViewオブジェクトを取得DosFileAttributeView view = Files.getFileAttributeView(path, DosFileAttributeView.class);
// BasicFileAttributeViewインターフェースで定義されたメソッドlong now = System.currentTimeMillis();view.setTime(FileTime.fromMillis(now), // 最終更新日時                   FileTime.fromMillis(now), // 最終アクセス日時                   FileTime.fromMillis(now)); // 作成日時
// DosFileAttributeViewインターフェースで定義されたメソッド// システムファイルとして設定するview.setSystem(true);

setTimeメソッドは、第1引数が最終更新日時、第2引数が最終アクセス日時、第3引数が

作成日時になります。これらの値を設定しない場合は、引数にnullを指定します。

そして、trueを引数にしてsetSystemメソッドをコールすることで、

ファイルをしsてむファイルとして設定しています。

同様に、PosixFileAttributeViewインターフェースを使用して、アトリビュートを設定してみます。

// 対象となるバスPath path = Paths.get("var.txt");
// POSIX準拠OS用のPosixFileAttributeViewオブジェクトを取得PosixFileAttributeView view  = Files.getFileAttributeView(path, PosixFileAttributeView.class);
// BasicFileAttributeViewインターフェースで定義されたメソッドlong now = System.currentTimeMillis();view.setTimes(FileTime.fromMillis(now), // 最終更新日時                    FileTime.fromMillis(now); // 最終アクセス日時                    FileTime.fromMillis(now)); // 作成日時
// アカウントの情報を取得UserPrincipalLookupService lookupService = FileSystems.getDefault().getUserPrincipalLookupService();UserPrincipal owner = LookupService.loolupPrincipalByName("sakuraba");
// PosixFileAttributeViewインターフェースで定義されたメソッドview.setOwner(owner);

PosixFileAttributeViewインターフェースでは、オーナやグループを設定することができます。

オーナはUserPrincipalインターフェース、グループはGroupPrincipalインターフェースで表します。

いずれもUserPrincipalLookupServiceクラスを使用し、既存アカウントやグループから検索します。

UserPrincipalLookupServiceオブジェクトを取得するためには、

FileSystemクラスのgetUserPrincipalLookupServiceメソッドを使用します。

そして、UserPrincipalオブジェクトを検索するにはlookupPrincipalByNameメソッドを使用します。

引数は文字列でアカウント名を指定します。

GroupPricipalオブジェクトを検索するにはlookupPrincipalByGroupNameを使用します。

引数はグループ名です。

そして、得られたUserPrincipalオブジェクトをsetOwnerメソッドで指定します。

このようにAttributeViewインターフェースのサブインターフェース群を使用することで、

アトリビュートをまとめて設定することが可能です。

それでは今日はこの辺にしておきましょう。

それではまた!
人気ブログランキングへ