New I/O APIはJavaプログラムにおける入出力機能を拡張する目的でJ2SE 1.4よりJavaプラットフォームに追加された機能である。実は当時リリースされたNew I/Oはまだ未完成な存在であり、その後も継続して仕様改定のための議論が続けられ、次期JavaプラットフォームとなるJava SE 7に追加される見通しとなっている。これは一般に「NIO.2」と呼ばれているもので、JSR 203として標準化が進められている。

なおNIO.2については以前、コラムで取り上げたことがあるが、今回レポートする内容はその後の最新動向ということになる。

Google社のCarl Quinn氏

Sun MicrosystemsのAlan Bateman氏

強力なファイルシステムAPI

まずNIO.2ではさまざまなファイルシステムを透過的に扱うための抽象的なインタフェースが用意される。これによって異なるファイルシステムに対する入出力を統一された方法で記述できるようになる。このAPIのためにjava.nio.filesystemとjava.nio.filesystem.attributeという2つの新しいパッケージが追加され、前者にはファイルシステムにアクセスするための機能が、後者にはファイルやディレクトリの属性を扱うための機能が提供されるという。

まずjava.nio.filesystemパッケージではファイルシステム上のリソースにアクセスするためのFileSystemクラスやファイルやディレクトリのパスを表すPathクラス、ファイルやパスへの参照を表すFileRefsクラスなどが用意される。たとえばPathクラスを利用した場合ファイルのコピーはリスト1.1のように行えるという。コピーの際にオプションを指定することができ、この例ではファイル属性は保持したままで、かつすでにファイルが存在する場合には置き換えるという指定を行っている。

リスト1 Pathを利用したファイルのコピー

Path source = Path.get("C:\\My Document\\Stuff.odp");
Path target = Path.get("D:\\Buckup\\MyStuff.odp");

// 通常のコピー
source.copyTo(target);
// オプションを指定してのコピー
source.copyTo(target, REPLACE_EXISTING, COPPY_ATTRIBUTES);

NIO.2ではシンボリックリンクも適切に扱うことができるようになる。ファイル属性にリンク情報を保持されるようになるためで、リスト1.2のようにすることで対象のファイルがシンボリックリンクであるかどうかや、リンク元のファイルのパスを調べることが可能となる。

リスト2 シンボリックリンクの扱い

Path file = Path.get("/user/spool1");

// ファイルの属性を読み込む
BasicFileAttributes attrs = Attributes.readBasicFileAttributes(file, false);

if (attrs.isSymbolicLink()) {
   // リンクのターゲットを読み込む
   Path target = file.readSymbolicLink();

   // 両ファイルが同じものかをチェック
   asert file.isSameFile(file.resolve(target)); 
}

ディレクトリに対する入出力機能も大幅に拡張されるという。たとえばディレクトリ内のファイルを連続して扱うためのストリームとしてDirectoryStreamクラスが追加される。リスト3はDirectoryStreamを利用して.java拡張子を持つファイルをすべて表示するコードの例だ。

リスト3 ディレクトリに対するストリーム

Path dir = Path.get("MyDir");

DirectoryStream stream = dir.newDirectoryStream("*.java");
try {
    for (DirectoryEntry entry : stream) {
        System.out.println(entry.getName());
    }
} finally {
  stream.close();
}

このほかにも高度なフィルタの設定やディレクトリツリーを容易に辿ることができる機能などが提供される予定だ。

java.nio.filesystems.attributesパッケージではファイルやディレクトリの属性を扱うための機能が提供される。NIO.2の属性へのアクセスはビューを介して行うモデルになっている。同パッケージにはさまざまなタイプの属性に対応したViewクラスや、各属性を表すAttributeインタフェースとその実装クラスが含まれるという。たとえば標準的なファイル属性の取得はBasicFileAttributeViewクラスを用いてリスト4のように行う。

リスト4 ファイル属性の取得

BasicFileAttributeView view = 
        file.newFileAttributeView(BasicFileAttributeView.class, true);
BasicFileAttributes attrs = view.readAttributes();

POSIXに対応したファイル属性を扱うこともでき、たとえばリスト5のようにすればUNIX形式のファイルパーミッションの取得や設定が可能である。

リスト5 POSIX属性の取り扱い

PosixFileAttributes attrs = 
        Attributes.readPosixAttributes(file, true);

// ファイルパーミッションの表示
String mode = PosixFilePermission.toString(attrs.permmisions());
System.out.format("%s %s %s", mode, attrs.owner(), attrs.group());

// ファイルパーミッションの設定
Attributes.setPosixFilePermissions(file, 
        OWNER_READ, OWNER_WRITE, GROUP_WRITE, OTHERS_READ);

その他、DOS形式のファイルの属性やACLs(Access Control Lists)形式の属性など、さまざまなファイル形式に対応する予定とのことである。

上記以外のファイルシステムAPIの特徴的な機能としては、ファイル変更通知機能が紹介された。これはファイルに対して各種変更が行われた場合にイベント形式で通知を受け取るための機能であり、リスト6のような感じで利用するという。

リスト6 ファイル変更の通知を受け取る

WatchService watcher = FileSystems.getDefault().newWatchService();

// 監視するイベントのタイプを設定
Set events = 
        EnumSet.of(ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
WatchKey key = dir.register(watcher, events);

// イベントの待ち受けと処理
for( ; ; ) { 
     key = watcher.take();

     for(WatchEevent> ev : key.pollEvents();) {
                if (event.getType() == ENTRY_MODIFY) {
              // ......
           }
     }

     key.reset();
}