Usando Java MappedByteBuffer

1. Información general

En este artículo rápido, veremos MappedByteBuffer en el paquete java.nio . Esta utilidad puede resultar muy útil para lecturas de archivos eficientes.

2. ¿Cómo MappedByteBuffer W orks

Cuando cargamos una región del archivo, podemos cargarla en la región de memoria particular a la que se puede acceder más tarde.

Cuando sabemos que necesitaremos leer el contenido de un archivo varias veces, es una buena idea optimizar el costoso proceso, por ejemplo, guardando ese contenido en la memoria. Gracias a eso, las búsquedas posteriores de esa parte del archivo irán solo a la memoria principal sin la necesidad de cargar los datos del disco, reduciendo sustancialmente la latencia.

Una cosa con la que debemos tener cuidado al usar MappedByteBuffer es cuando trabajamos con archivos muy grandes desde un disco; debemos asegurarnos de que el archivo quepa en la memoria .

De lo contrario, podemos llenar toda la memoria y, como consecuencia, encontrarnos con la excepción OutOfMemoryException común . Podemos solucionarlo cargando solo una parte del archivo, basándonos, por ejemplo, en patrones de uso.

3. Leyendo el archivo usando MappedByteBuffer

Digamos que tenemos un archivo llamado fileToRead.txt con el siguiente contenido:

This is a content of the file

El archivo se encuentra en el directorio / resource por lo que podemos cargarlo usando la siguiente función:

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

Para crear MappedByteBuffer desde un archivo, primero necesitamos crear un FileChannel a partir de él. Una vez que tenemos nuestro canal creado, podemos invocar el método map () en él pasando en MapMode, una posición desde la que queremos leer y el parámetro de tamaño que especifica cuántos bytes 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); } }

Una vez que asignamos nuestro archivo al búfer asignado a la memoria, podemos leer los datos en el CharBuffer. Es importante notar que aunque estamos leyendo el contenido del archivo cuando llamamos al método decode () pasando MappedByteBuffer, leemos desde la memoria, no desde el disco. Por tanto, esa lectura será muy rápida.

Podemos afirmar que el contenido que leemos de nuestro archivo es el contenido real del archivo fileToRead.txt :

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

Cada lectura posterior del mappedByteBuffer será muy rápida porque el contenido del archivo se asigna en la memoria y la lectura se realiza sin necesidad de buscar datos en el disco.

4. Escribir en el archivo usando MappedByteBuffer

Digamos que queremos escribir algún contenido en el archivo fileToWriteTo.txt usando la API MappedByteBuffer . Para lograrlo, necesitamos abrir FileChannel y llamar al método map () en él, pasando FileChannel.MapMode.READ_WRITE.

A continuación, podemos guardar el contenido del CharBuffer en el archivo usando el método put () del MappedByteBuffer:

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 el contenido real de charBuffer se escribió en el archivo leyendo su contenido:

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

5. Conclusión

En este tutorial rápido, estábamos buscando en el MappedByteBuffer construcción de la java.nio paquete.

Esta es una forma muy eficiente de leer el contenido del archivo varias veces, ya que el archivo se asigna a la memoria y las lecturas posteriores no necesitan ir al disco cada vez.

Todos estos ejemplos y fragmentos de código se pueden encontrar en GitHub: este es un proyecto de Maven, por lo que debería ser fácil de importar y ejecutar tal como está.