Usando Java MappedByteBuffer

Usando JavaMappedByteBuffer

1. Visão geral

Neste artigo rápido, veremosMappedByteBuffer no pacotejava.nio. Este utilitário pode ser bastante útil para leituras de arquivos eficientes.

2. ComoMappedByteBuffer Wfunciona

Quando estamos carregando uma região do arquivo, podemos carregá-lo na região específica da memória que pode ser acessada mais tarde.

Quando sabemos que precisaremos ler o conteúdo de um arquivo várias vezes, é uma boa ideia otimizar o processo caro, por exemplo, salvando esse conteúdo na memória. Graças a isso, as pesquisas subseqüentes dessa parte do arquivo irão apenas para a memória principal, sem a necessidade de carregar os dados do disco, reduzindo a latência substancialmente.

Uma coisa com a qual precisamos ter cuidado ao usarMappedByteBuffer é quando estamos trabalhando com arquivos muito grandes do disco -we need to make sure the file will fit in memory.

Caso contrário, podemos preencher toda a memória e, como consequência, encontrar osOutOfMemoryException. comuns. Podemos superar isso carregando apenas parte do arquivo - com base, por exemplo, nos padrões de uso.

3. Lendo o arquivo usandoMappedByteBuffer

Digamos que temos um arquivo chamadofileToRead.txt com o seguinte conteúdo:

This is a content of the file

O arquivo está localizado no diretório/resource para que possamos carregá-lo usando a seguinte função:

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

Para criar oMappedByteBuffer de um arquivo, primeiro precisamos criar umFileChannel a partir dele. Assim que tivermos nosso canal criado, podemos invocar o métodomap() nele passando oMapMode,aposition do qual queremos ler, e o parâmetrosize que especifica como muitos bytes que queremos:

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);
    }
}

Depois de mapear nosso arquivo no buffer mapeado de memória, podemos ler os dados dele noCharBuffer.. Importante notar é que, embora estejamos lendo o conteúdo do arquivo quando chamamos a passagem do métododecode() MappedByteBuffer, lemos da memória, não do disco. Portanto, essa leitura será muito rápida.

Podemos afirmar que o conteúdo que lemos em nosso arquivo é o conteúdo real do arquivofileToRead.txt:

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

Cada leitura subseqüente demappedByteBuffer será muito rápida porque o conteúdo do arquivo é mapeado na memória e a leitura é feita sem a necessidade de consultar dados do disco.

4. Gravando no arquivo usandoMappedByteBuffer

Digamos que queremos escrever algum conteúdo no arquivofileToWriteTo.txt usando a APIMappedByteBuffer. Para conseguir isso, precisamos abrir oFileChannele chamar o métodomap() nele, passando oFileChannel.MapMode.READ_WRITE.

Em seguida, podemos salvar o conteúdo deCharBuffer no arquivo usando o métodoput() doMappedByteBuffer:

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));
    }
}

Podemos afirmar que o conteúdo real decharBuffer foi gravado no arquivo lendo o conteúdo dele:

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

5. Conclusão

Neste tutorial rápido, vimos a construçãoMappedByteBuffer do pacotejava.nio.

Essa é uma maneira muito eficiente de ler o conteúdo do arquivo várias vezes, pois o arquivo é mapeado na memória e as leituras subsequentes não precisam ir ao disco todas as vezes.

Todos esses exemplos e trechos de código podem ser encontradosover on GitHub - este é um projeto Maven, portanto, deve ser fácil de importar e executar como está.