1. 概要

このクイック記事では、 java.nioパッケージのMappedByteBufferについて説明します。 このユーティリティは、効率的なファイル読み取りに非常に役立ちます。

2. MappedByteBuffer Worksの方法

ファイルの領域をロードするときに、後でアクセスできる特定のメモリ領域にファイルをロードできます。

ファイルの内容を複数回読み取る必要があることがわかっている場合は、コストのかかるプロセスを最適化することをお勧めします。 そのコンテンツをメモリに保存します。 そのおかげで、ファイルのその部分の後続のルックアップは、ディスクからデータをロードする必要なしにメインメモリにのみ移動し、レイテンシーを大幅に削減します。

MappedByteBuffer を使用するときに注意する必要があるのは、ディスクからの非常に大きなファイルを操作する場合です。ファイルがメモリに収まるようにする必要があります

そうしないと、メモリ全体がいっぱいになり、その結果、共通の問題が発生する可能性があります OutOfMemoryException。 たとえば使用パターンに基づいて、ファイルの一部のみをロードすることで、これを克服できます。

3. MappedByteBufferを使用したファイルの読み取り

次の内容のfileToRead.txtというファイルがあるとします。

This is a content of the file

このファイルは/resource ディレクトリにあるため、次の関数を使用してロードできます。

Path getFileURIFromResources(String fileName) throws Exception {
    ClassLoader classLoader = getClass().getClassLoader();
    return Paths.get(classLoader.getResource(fileName).getPath());
}

ファイルからMappedByteBufferを作成するには、まずファイルからFileChannelを作成する必要があります。 チャネルを作成したら、 map()メソッドを呼び出して、読み取りたい MapMode、 a 位置を渡し、必要なバイト数を指定するsizeパラメーター:

CharBuffer charBuffer = null;
Path pathToRead = getFileURIFromResources("fileToRead.txt");

try (FileChannel fileChannel (FileChannel) Files.newByteChannel(
  pathToRead, EnumSet.of(StandardOpenOption.READ))) {
 
    MappedByteBuffer mappedByteBuffer = fileChannel
      .map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());

    if (mappedByteBuffer != null) {
        charBuffer = Charset.forName("UTF-8").decode(mappedByteBuffer);
    }
}

ファイルをメモリマップドバッファにマッピングすると、ファイルからデータを読み込んで CharBuffer。 注意すべき重要な点は、ファイルの内容を読んでいるのに、 decode() メソッドの受け渡し MappedByteBuffer、 ディスクからではなく、メモリから読み取ります。 したがって、その読み取りは非常に高速になります。

ファイルから読み取ったコンテンツは、fileToRead.txtファイルの実際のコンテンツであると断言できます。

assertNotNull(charBuffer);
assertEquals(
  charBuffer.toString(), "This is a content of the file");

mappedByteBuffer からの後続のすべての読み取りは、ファイルのコンテンツがメモリにマップされ、ディスクからデータを検索する必要なしに読み取りが行われるため、非常に高速になります。

4. MappedByteBufferを使用したファイルへの書き込み

MappedByteBuffer APIを使用して、ファイルfileToWriteTo.txtにコンテンツを書き込みたいとします。 それを達成するには、 FileChannel と呼び出す地図() その上でメソッド、渡す FileChannel.MapMode.READ_WRITE。

次に、 MappedByteBuffer: put()メソッドを使用して、CharBufferの内容をファイルに保存できます。

CharBuffer charBuffer = CharBuffer
  .wrap("This will be written to the file");
Path pathToWrite = getFileURIFromResources("fileToWriteTo.txt");

try (FileChannel fileChannel = (FileChannel) Files
  .newByteChannel(pathToWrite, EnumSet.of(
    StandardOpenOption.READ, 
    StandardOpenOption.WRITE, 
    StandardOpenOption.TRUNCATE_EXISTING))) {
    
    MappedByteBuffer mappedByteBuffer = fileChannel
      .map(FileChannel.MapMode.READ_WRITE, 0, charBuffer.length());
    
    if (mappedByteBuffer != null) {
        mappedByteBuffer.put(
          Charset.forName("utf-8").encode(charBuffer));
    }
}

charBuffer の実際の内容は、ファイルの内容を読み取ることでファイルに書き込まれたと断言できます。

List<String> fileContent = Files.readAllLines(pathToWrite);
assertEquals(fileContent.get(0), "This will be written to the file");

5. 結論

このクイックチュートリアルでは、java.nioパッケージのMappedByteBufferコンストラクトを見ていました。

これは、ファイルがメモリにマップされ、後続の読み取りが毎回ディスクに移動する必要がないため、ファイルのコンテンツを複数回読み取るための非常に効率的な方法です。

これらの例とコードスニペットはすべて、GitHubにあります。これはMavenプロジェクトであるため、そのままインポートして実行するのは簡単です。