Utilizzo di Java MappedByteBuffer

1. Panoramica

In questo rapido articolo, esamineremo MappedByteBuffer nel pacchetto java.nio . Questa utility può essere molto utile per una lettura efficiente dei file.

2. Come MappedByteBuffer W orks

Quando stiamo caricando una regione del file, possiamo caricarla nella particolare regione di memoria a cui è possibile accedere in seguito.

Quando sappiamo che avremo bisogno di leggere più volte il contenuto di un file, è una buona idea ottimizzare il processo costoso, ad esempio salvando quel contenuto nella memoria. Grazie a ciò, le successive ricerche di quella parte del file andranno solo nella memoria principale senza la necessità di caricare i dati dal disco, riducendo sostanzialmente la latenza.

Una cosa a cui dobbiamo stare attenti quando usiamo MappedByteBuffer è quando lavoriamo con file molto grandi dal disco: dobbiamo assicurarci che il file si adatti alla memoria .

Altrimenti, possiamo riempire l'intera memoria e, di conseguenza, incappare nella comune OutOfMemoryException. Possiamo ovviare caricando solo una parte del file, ad esempio in base ai modelli di utilizzo.

3. Lettura del file utilizzando MappedByteBuffer

Supponiamo di avere un file chiamato fileToRead.txt con il seguente contenuto:

This is a content of the file

Il file si trova nella directory / resource quindi possiamo caricarlo utilizzando la seguente funzione:

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

Per creare il MappedByteBuffer da un file, prima dobbiamo creare un FileChannel da esso. Una volta creato il nostro canale, possiamo invocare il metodo map () su di esso passando il MapMode, una posizione da cui vogliamo leggere, e il parametro size che specifica quanti byte vogliamo:

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 volta mappato il nostro file nel buffer mappato in memoria, possiamo leggere i dati da esso nel CharBuffer. È importante notare che sebbene stiamo leggendo il contenuto del file quando chiamiamo il metodo decode () passando MappedByteBuffer, leggiamo dalla memoria, non dal disco. Quindi quella lettura sarà molto veloce.

Possiamo affermare che il contenuto che leggiamo dal nostro file è il contenuto effettivo del file fileToRead.txt :

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

Ogni lettura successiva dal mappedByteBuffer sarà molto veloce perché il contenuto del file viene mappato in memoria e la lettura viene eseguita senza la necessità di cercare i dati dal disco.

4. Scrittura sul file utilizzando MappedByteBuffer

Supponiamo di voler scrivere del contenuto nel file fileToWriteTo.txt utilizzando l' API MappedByteBuffer . Per ottenere ciò dobbiamo aprire il FileChannel e chiamare il metodo map () su di esso, passando FileChannel.MapMode.READ_WRITE.

Successivamente, possiamo salvare il contenuto di CharBuffer nel file utilizzando il metodo put () da 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)); } }

Possiamo affermare che il contenuto effettivo di charBuffer è stato scritto nel file leggendone il contenuto:

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

5. conclusione

In questo breve tutorial, stavamo esaminando il costrutto MappedByteBuffer dal pacchetto java.nio .

Questo è un modo molto efficiente per leggere più volte il contenuto del file, poiché il file viene mappato in memoria e le letture successive non devono essere trasferite ogni volta su disco.

Tutti questi esempi e frammenti di codice possono essere trovati su GitHub: questo è un progetto Maven, quindi dovrebbe essere facile da importare ed eseguire così com'è.