待望のNIO.2の全貌が明らかに

J2SE 1.4がリリースされたのはもう5年も前のことだが、そのときに追加されたAPIに入出力機能を拡張する「New I/O」がある。New I/OははJSR 51として標準化されているAPIで、バッファを用いた入出力やノンブロッキング入出力、ファイルのロックやメモリへのマッピングなどといった機能を提供する。これらの機能は非常に強力であり、入出力の効率を上げるには不可欠の存在だが、一方で未完成な部分が多々あり、JCPでは後継となる「NIO.2」の策定作業が進められていた。

4月12日、そのNIO.2のEarly Draftがついに公開された。NIO.2の仕様策定は「JSR 203: More New I/O APIs for the Java Platform ("NIO.2")」として進められており、これが最終的にJava SE 7に取り込まれる予定になっていることはすでに本連載の第5回でも触れた通りである。

NIO.2では以下の3つを主な課題として掲げている。

  • ファイルシステムに対する新しいインタフェースの提供
  • ソケットやファイルに対する非同期入出力操作の実現
  • NIOのソケットチャネル機能の完成

公開されたEarly DraftはJCPのサイトからダウンロードすることができる。さっそくその中身を確認してみよう。なお、スペックリードであるAlan Bateman氏のブログではNIO.2の概要を紹介したスライドも公開されているので、そちらも参照してもらいたい。

新しいファイルシステムAPI

NIO.2では抽象的なファイルシステムインタフェースを用意することで、さまざまなファイルシステムを透過的に扱うことができる。たとえばSMBやFTP、SMTP、データベースなどを、ローカルファイルシステムと同様に扱えるようになる。

ファイルシステムにアクセスする方法は、新たに追加されたjava.nio.filesystemsパッケージのクラス/インタフェースによって提供される。また、ファイルシステムのためのサービスプロバイダはjava.nio.filesystems.spiパッケージに用意されている。

java.nio.filesystemsパッケージにはファイルシステムにアクセスするためのFileSystemクラスが定義されている。APIドキュメントを見た限りだと、FileSystemオブジェクトはFileSystemsクラスを利用してリスト1のようにして取得できるようだ。FileSystemsのnewFileSystem()メソッドは、FileSystemProvider.providers()メソッドによってその環境で利用できるファイルシステムプロバイダを取得し、そこからFileSystemオブジェクトを取得して返す。

リスト1 FileSystemオブジェクトの取得

FileSystem fileSystem = FileSystems.newFileSystem("/default/directory", false);

また、リスト2のようにすることでプラットフォームのデフォルトのFileSystemを取得することができ、これが既存のjava.io.Fileクラスを使ったファイルへのアクセスと同等のものになっているらしい。

リスト2 デフォルトのFileSystemオブジェクトの取得

FileSystem fileSystem = FileSystems.getDefault();

java.nio.filesystemsパッケージには、そのほかにもファイルやディレクトリのパスを表すPathクラスや、ファイルやパスに対する参照を表すFileReference/PathReferenceクラスなどが定義されている。PathやPathReferenceなどのオブジェクトはFileSystemオブジェクトから取得し、実際にファイルファイルやディレクトリの操作を行うことができる。また、これらのクラスによってシンボリックリンクなども適切に扱うことができるようになる。

java.nio.filesystemsパッケージにはサブパッケージとしてjava.nio.filesystems.attributesというパッケージが用意されている。名前からもわかるように、このパッケージではファイルやファイルシステムの属性にアクセスするためのクラス/インタフェースが提供される。

java.nio.filesystems.attributesパッケージでは属性に対するViewを定義したAttributeViewインタフェースとその実装クラスが用意されており、これによってさまざまなタイプの属性にアクセスすることができる。また、各属性を表すAttributeインタフェースとその実装クラスもこのパッケージで提供される。

たとえばサイズや更新日時などといった標準のファイル属性は、リスト3のようにして取得する。

リスト3 ファイル属性へのアクセス

FileReference file = ...;
BasicAttributes attrs = file.readBasicFileAttributes();
long size = attrs.getSize();                    // ファイルサイズを取得
long modifiedTime = getLastModifiedTime();      // 最終更新時間を取得

また、Viewを用いればリスト4のようにして属性を変更することができる。

リスト4 ファイル属性の変更

FileReference file = ...;
BasicFileAttributeView view = 
    file.newFileAttributeView(BasicFileAttributeView.class);
view.updateLastModifiedTime(System.currentTimeMillis(), TimeUnit.MILLISECONDS);

非同期入出力

NIO.2ではファイルとソケットの両方で非同期入出力がサポートされる。java.nio.channelsパッケージには非同期入出力のためのチャネルを定義したAsynchronousChannelクラスと、そのサブクラスであるAsynchronousFileChannel、AsynchronousSocketChannel、AsynchronousServerSocketChannel、AsynchronousDatagramChannelが用意されている。これらのクラスは、名前の通りファイルやソケットへの非同期アクセスを可能にする。

たとえば、非同期のソケットチャネルからデータを読み込むコードとしてはリスト5のような例が挙げられている。

リスト5 非同期ソケットの使用例

AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();

channel.read(buffer, new CompletionHandler() {
    public void completed(IoFuture result) {
        try {  
            int bytesRead = result.getNow();
               ...
            } catch (ExecutionException x) { 
               ...
        }
    }
});

ここで使われているCompletionHandlerインタフェースは、非同期通信が終了した際に実行する処理を記述するためのハンドラである。IoFutureインタフェースはjava.util.concurrent.Futureのサブインタフェースで、非同期通信操作に対する結果を表す。

その他、NIO.2ではAsynchronousChannelGroupクラスを使用することで非同期チャネルをグループ化して扱うこともできるようになっている。

ソケットチャネル

ソケットチャネル機能についてはJSR 51の段階でもすでに実装されていたが、当初の目的に対して未完成な部分も多く、NIO.2ではその完成が望まれていた部分でもある。したがってNIO.2ではソケットチャネルの機能を提供するjava.nio.channelsパッケージに対して大幅な修正が加えられた。例えば、以下のような点が変更されている。

  • NetworkChannelインタフェースが追加され、ネットワークに対するチャネルのクラス(SocketChannel、ServerSocketChannelなど)がこれをimplementsするようになった
  • 各チャネルに対して細かな修正が加えられた
  • ソケットオプションを指定するためのSocketOptionクラスが追加された
  • MulticastChannelインタフェースが追加され、データグラムチャネルのクラス(DatagramChannelなど)がこれをimplementsするようになった
  • データグラムチャネルを開く際にプロトコルファミリーを指定する

なお公開されたAPIドキュメントには変更点が[new]や[revised]などとして明記されているので、詳細はそちらを参照して欲しい。

NIO.2のEarly Draft Reviewは5月27日まで続けられ、エキスパートグループに同ドラフトに関するフィードバックを送ることができる。また、NIO.2について議論をするためのメーリングリストも用意されており、誰でも自由に参加することができるようになっている。