1. 序章

このチュートリアルでは、Java IO機能と、それらがさまざまなJavaバージョン間でどのように変化したかについて説明します。 最初に、最初のJavaバージョンの java.ioパッケージについて説明します。 次に、Java1.4で導入されたjava.nioパッケージについて説明します。 最後に、一般にNIO.2パッケージとして知られる java.nio.fileパッケージについて説明します。

2. JavaNIOパッケージ

最初のJavaバージョンはjava.ioパッケージでリリースされ、ファイルシステムにアクセスするためのファイルクラスが導入されました。 Fileクラスはファイルとディレクトリを表し、ファイルシステム上で制限された操作を提供します。ファイルの作成と削除、ファイルの存在の確認、読み取り/書き込みアクセスの確認などが可能でした。

また、いくつかの欠点があります。

  • コピーメソッドの欠如–ファイルをコピーするには、2つのファイルインスタンスを作成し、バッファーを使用して1つのインスタンスから読み取り、別のファイルインスタンスに書き込む必要があります。
  • 不正なエラー処理–一部のメソッドは、操作が成功したかどうかを示すインジケーターとしてbooleanを返します。
  • 限られたファイル属性のセット–名前、パス、読み取り/書き込み権限、メモリサイズが利用可能です。
  • ブロックAPI–IO操作が完了するまでスレッドはブロックされます。

ファイルを読み取るには、ファイルからバイトを読み取るためのFileInputStreamインスタンスが必要です。

@Test
public void readFromFileUsingFileIO() throws Exception {
    File file = new File("src/test/resources/nio-vs-nio2.txt");
    FileInputStream in = new FileInputStream(file);
    StringBuilder content = new StringBuilder();
    int data = in.read();
    while (data != -1) {
        content.append((char) data);
        data = in.read();
    }
    in.close();
    assertThat(content.toString()).isEqualTo("Hello from file!");
}

次に、Java 1.4では、 java.nio パッケージにバンドルされているノンブロッキングIOAPIが導入されています(nioは新しいIOの略です)。 NIOは、java.ioパッケージの制限を克服するために導入されました。 このパッケージでは、チャネルバッファー、およびセレクターの3つのコアクラスが導入されました。

2.1. チャネル

Java NIOチャネルは、バッファの読み取りと書き込みを可能にするクラスです。チャネルクラスは、 Streams (ここではIO について説明します)に似ています。 Streams 、Java 1.8 Streams )ではなく、いくつかの違いがあります。 Channel は双方向ですが、 Streams は通常、一方向です。非同期で読み取りと書き込みを行うことができます。

Channel クラスには、ファイルシステムの読み取り/書き込み用の FileChannel 、UDPを使用したネットワーク経由の読み取り/書き込み用の DatagramChannel などの実装がいくつかあります。 ] SocketChannelTCPを使用したネットワーク上での読み取り/書き込み用。

2.2. バッファ

バッファは、データの読み取りまたは書き込みができるメモリのブロックです。 NIO Buffer オブジェクトは、メモリブロックをラップします。 Buffer クラスは、メモリブロックを操作するための一連の機能を提供します。 Buffer オブジェクトを操作するには、 Buffer クラスの3つの主要なプロパティ、容量、位置、および制限を理解する必要があります。

  • 容量は、メモリブロックのサイズを定義します。 バッファにデータを書き込む場合、限られた長さしか書き込むことができません。 バッファがいっぱいになったら、データを読み取るか、クリアする必要があります。
  • 位置は、データを書き込む開始点です。 空のバッファは0から始まり、容量–1になります。 また、データを読み取るときは、位置の値から開始します。
  • 制限とは、バッファからの書き込みと読み取りの方法を意味します。

Bufferクラスには複数のバリエーションがあります。 ブールタイプとMappedByteBufferを除く、プリミティブJavaタイプごとに1つ。

バッファを操作するには、いくつかの重要な方法を知る必要があります。

  • alllocate(int value)– このメソッドを使用して、特定のサイズのバッファーを作成します。
  • flip() –このメソッドは、書き込みモードから読み取りモードに切り替えるために使用されます
  • clear()–バッファの内容をクリアするためのメソッド
  • compact()–すでに読んだコンテンツのみをクリアするメソッド
  • rewind()– は位置を0にリセットして、バッファー内のデータを再読み取りできるようにします

前述の概念を使用して、ChannelクラスとBufferクラスを使用して、ファイルからコンテンツを読み取ります。

@Test
public void readFromFileUsingFileChannel() throws Exception {
    RandomAccessFile file = new RandomAccessFile("src/test/resources/nio-vs-nio2.txt", "r");
    FileChannel channel = file.getChannel();
    StringBuilder content = new StringBuilder();
    ByteBuffer buffer = ByteBuffer.allocate(256);
    int bytesRead = channel.read(buffer);
    while (bytesRead != -1) {
        buffer.flip();
        while (buffer.hasRemaining()) {
            content.append((char) buffer.get());
        }
        buffer.clear();
        bytesRead = channel.read(buffer);
    }
    file.close();
    assertThat(content.toString()).isEqualTo("Hello from file!");
}

必要なすべてのオブジェクトを初期化した後、チャネルからバッファに読み込みます。 次に、whileループで、 flip()メソッドを使用して読み取り用にバッファーにマークを付け、一度に1バイトずつ読み取り、結果に追加します。 最後に、データをクリアして別のバッチを読み取ります。

2.3. セレクター

Java NIO Selectorを使用すると、1つのスレッドで複数のチャネルを管理できます。 セレクターオブジェクトを使用して複数のチャネルを監視するには、各チャネルインスタンスが非ブロッキングモードである必要があり、それを登録する必要があります。 チャネル登録後、チャネルとセレクター間の接続を表すSelectionKeyオブジェクトを取得します。 セレクターに複数のチャンネルを接続している場合は、 select()メソッドを使用して、使用できるチャンネルの数を確認できます。 select()メソッドを呼び出した後、 selectedKeys()メソッドを使用して、準備ができているすべてのチャネルをフェッチできます。

2.4. NIOパッケージの欠点

導入されたjava.nioパッケージの変更は、低レベルのデータIOに関連しています。 非ブロッキングAPIを許可しましたが、他の側面には問題が残っていました。

  • シンボリックリンクの限定サポート
  • ファイル属性アクセスの制限付きサポート
  • より優れたファイルシステム管理ツールがありません

3. JavaNIO.2パッケージ

Java 1.7では、NIO.2パッケージとも呼ばれる新しいjava.nio.fileパッケージが導入されています。 このパッケージは、java.nioパッケージでサポートされていない非ブロッキングIOへの非同期アプローチに従います。 最も重要な変更は、高レベルのファイル操作に関連しています。 これらは、 Files、Path、、およびPathsクラスで追加されます。 最も注目すべき低レベルの変更は、AsynchroniousFileChannelAsyncroniousSocketChannelの追加です。

Pathオブジェクトは、区切り文字で区切られたディレクトリとファイル名の階層シーケンスを表します。 ルートコンポーネントは最も左にあり、ファイルは右にあります。 このクラスは、 getFileName() getParent()などのユーティリティメソッドを提供します。 Path クラスは、異なるファイル間のパスを構築するのに役立つresolveおよびrelativizeメソッドも提供します。 Pathsクラスは、StringまたはURIを受け取ってPathインスタンスを作成する静的ユーティリティメソッドのセットです。

Filesクラスは、前述のPathクラスを使用し、ファイル、ディレクトリ、およびシンボリックリンクを操作するユーティリティメソッドを提供します。また、 readAttributes()メソッドを使用して多くのファイル属性を読み取る方法も提供します。 。

最後に、ファイルの読み取りに関して、NIO.2が以前のIOバージョンとどのように比較されるかを見てみましょう。

@Test
public void readFromFileUsingNIO2() throws Exception {
    List<String> strings = Files.readAllLines(Paths.get("src/test/resources/nio-vs-nio2.txt"));
    assertThat(strings.get(0)).isEqualTo("Hello from file!");
}

4. 結論

この記事では、java.nioおよびjava.nio.fileパッケージの基本について説明しました。 ご覧のとおり、NIO.2はNIOパッケージの新しいバージョンではありません。 NIOパッケージは非ブロッキングIO用の低レベルAPIを導入しましたが、NIO.2はより優れたファイル管理を導入しました。 これらの2つのパッケージは同義ではなく、相互に補完し合っています。 いつものように、すべてのコードサンプルはGitHubにあります。