Java MappedByteBuffer (2024)
As read-write operation on large files is always more expensive, in order to handle large file data, Java has provided an efficient way to load the portion of file data into virtual memory and to perform read / write operations more quickly.
Java 7 introduced the MappedByteBuffer class as part of the java.nio package used to create JVM virtual memory mapping.
We use FileChannel.map method to create MappedByteBuffers, which loads file data into virtual memory instead of heap.
Let's first understand core building block used for MappedByteBuffer.
Buffer (ByteBuffer Class) is an array of bytes which holds data that to be read or written.
Stream- oriented I/O , input stream produces one byte data and outputstream consume 1 byte of data.
Block oriented I/O, input/output stream produces/consumes block of data in one go.
With Streams, we can either read or write one at a time, whereas Channel support both read and write at same time.
File Channel always read/write from buffer. So first we put data into buffer and sent to channel. File Channel is
thread safe, as read/write can be done asynchronously, only one thread can update file data at a time.
What is RandomAccessFile
A random access file is like a large array of bytes stored in the file system. Internally Java uses File Pointer to is like an index or cursor. Input data can be read from input byte array from the position where file pointer is pointing and move the file pointer position as we read the input byte array of data. We are going to learn how to read and write content from a memory mapped file using RandomAccessFile and MemoryMappedBuffer. By using instances of RandomAccessFile Class , we can read and write to a random access file.Declaration
public class RandomAccessFile
extends Object
implements DataOutput, DataInput, Closeable
RandomAccessFile Example
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAccessFileSample {
static final String noteFile ="notes.txt";
public static void main(String[] args) {
try {
System.out.println(new String(readFromFile(noteFile, 0, 15)));
writeToFile(noteFile, "Add a new note in Notes Example", 21);
} catch (IOException e) {
e.printStackTrace();
}
}
private static byte[] readFromNoteFile(String noteFile, int position, int size)
throws IOException {
RandomAccessFile fileToRead = new RandomAccessfileToRead(noteFile, "r");
fileToRead.seek(position);
byte[] byteToRead = new byte[size];
fileToRead.read(byteToRead);
fileToRead.close();
return byteToRead;
}
private static void writeToNoteFile(String noteFile, String data, int position)
throws IOException {
RandomAccessFile fileToWrite = new RandomAccessFile(noteFile, "rw");
fileToWrite.seek(position);
fileToWrite.write(data.getbyteToRead());
fileToWrite.close();
}
}
Note : MemoryMappedBuffer has a fixed size, so be careful while loading the large file from the disk, as it would throw some unexpected error like OutOfMemoryException.
Reading data using MemoryMappedBuffer
Load the file from the resource directory.Path getFileURIFromResources(final String fileName) throws Exception {
ClassLoader classLoader = getClass().getClassLoader();
return Paths.get(classLoader.getResource(fileName).getPath());
}
We use Byte buffer, whose content is a memory-mapped region of a file. Mapped byte buffers are created via the MappedByteBuffer.map method. A mapped byte buffer and the file mapping that it represents remain valid until the buffer itself is garbage-collected.
CharBuffer charBuffer = null;
Path pathToRead = getFileURIFromResources("notes.txt");
try (MappedByteBuffer MappedByteBuffer (MappedByteBuffer) Files.newByteChannel(
pathToRead, EnumSet.of(StandardOpenOption.READ))) {
MappedByteBuffer mappedByteBuffer = MappedByteBuffer
.map(MappedByteBuffer.MapMode.READ_ONLY, 0, MappedByteBuffer.size());
if (mappedByteBuffer != null) {
charBuffer = Charset.forName("UTF-8").decode(mappedByteBuffer);
}
}
Writing to the File using MappedByteBuffer
To write to the file, first we need to open the MappedByteBuffer and acll the map. You can see we are using READ_WRITE mode, to write the data to MappedByteBuffer.CharBuffer charBuffer = CharBuffer
.wrap("Add notes in the file");
Path pathToWrite = getFileURIFromResources("Notes.txt");
try (MappedByteBuffer MappedByteBuffer = (MappedByteBuffer) Files
.newByteChannel(pathToWrite, EnumSet.of(
StandardOpenOption.READ,
StandardOpenOption.WRITE,
StandardOpenOption.TRUNCATE_EXISTING))) {
MappedByteBuffer mappedByteBuffer = MappedByteBuffer
.map(MappedByteBuffer.MapMode.READ_WRITE, 0, charBuffer.length());
if (mappedByteBuffer != null) {
mappedByteBuffer.put(
Charset.forName("utf-8").encode(charBuffer));
}
}