Using FileChannel.map() allows you to map a region of a file directly into memory. This creates a MappedByteBuffer, which acts like a bridge between your application’s memory and the file on disk. The operating system handles the actual reading and writing in the background, making it extremely efficient for large files.
Here is how you can use it for both reading and writing.
1. Reading from a Memory-Mapped File
To read, open the channel with StandardOpenOption.READ and use MapMode.READ_ONLY.
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
public class MemoryMappedExample {
public void readMappedFile(Path path) throws IOException {
try (FileChannel channel = FileChannel.open(path, StandardOpenOption.READ)) {
long size = channel.size();
// Map the entire file for reading
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, size);
// Access data directly from memory
while (buffer.hasRemaining()) {
byte b = buffer.get();
// Process byte...
}
}
}
}
2. Writing to a Memory-Mapped File
To write, you must open the channel with both READ and WRITE options (even if you only intend to write) and use MapMode.READ_WRITE.
public void writeMappedFile(Path path) throws IOException {
// Files must be opened for both READ and WRITE to use MapMode.READ_WRITE
try (FileChannel channel = FileChannel.open(path,
StandardOpenOption.READ,
StandardOpenOption.WRITE,
StandardOpenOption.CREATE)) {
long size = 1024 * 1024; // Map 1MB
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, size);
// Writing to the buffer automatically writes to the file
buffer.putInt(12345);
buffer.put("Hello Memory!".getBytes());
// Force changes to storage to ensure they are written to disk
buffer.force();
}
}
Key Considerations
- Map Modes:
READ_ONLY: Any attempt to modify the buffer results in aReadOnlyBufferException.READ_WRITE: Changes to the buffer are eventually propagated to the file.PRIVATE: “Copy-on-write” mode. Changes are local to the buffer and not saved to the file.
- Size Limits: On 32-bit JVMs, you cannot map more than 2GB at once because of address space limits. On 64-bit systems, you can map much larger regions, but a single
MappedByteBufferis still limited toInteger.MAX_VALUEbytes (approx 2GB). To handle larger files, you must create multiple mappings. - Performance: Memory mapping is most beneficial for large files accessed frequently or randomly. For small, sequential reads, standard
BufferedInputStreammight be simpler and just as fast. - Unmapping: Java does not provide an explicit “unmap” method. The mapping remains until the
MappedByteBufferobject is garbage collected. Closing theFileChanneldoes not unmap the file.
