How do I use memory mapped files with FileChannel.map()?

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 a ReadOnlyBufferException.
    • 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 MappedByteBuffer is still limited to Integer.MAX_VALUE bytes (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 BufferedInputStream might be simpler and just as fast.
  • Unmapping: Java does not provide an explicit “unmap” method. The mapping remains until the MappedByteBuffer object is garbage collected. Closing the FileChannel does not unmap the file.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.