Search this site
What do you think of this article? Did it help you? Found a mistake? Feedback and suggestions here
Mapped buffers (file mapping)
The NIO framework provides the facility to map sections of a file to a ByteBuffer. Once the mapping is set up, reading from the buffer automatically reads data from the corresponding section of the file, and writing to the buffer similarly results in the contents of the file being updated accordingly.
This facility to create a mapped byte buffer can be useful in cases where one or more of the following are true:
Note that there isn't necessarily any benefit in using a mapped byte buffer in terms of "raw" read/write performance. For example, if you are simply reading or writing serially through a file, then in terms of performance, you generally may as well use a plain old FileInputStream or FileOutputStream— with appropriate buffering, of course. Similarly, accessing a file via a mapped buffer— at least under Windows— doesn't appear to have any impact on the performance of file accesses by other means. For example, if you (a) map the contents of a file, (b) read the data via the mapped buffer, then (c) read that same file via a normal FileInputStream, the "normal" read in (c) will generally benefit from the caching that occurs in (b).
Therefore, the decision to use a mapped byte buffer should really be made on the basis of the functionality you require: is accessing the file data via a ByteBuffer the most convenient means for your application? Is it desirable for your application to take advantage of the virtual memory system (mapped buffers, not being part of the Java heap, are eligible to be paged in/out as memory permits), or is more consistent access time beneficial to your application?
How to use a mapped ByteBuffer
If it is, then to set up a mapped buffer, you first need to obtain a FileChannel. Recall that to do so, you first open the file via one of the regular means (RandomAccessFile, FileInputSteam or FileOutputStream), then call the getChannel() method. Finally, you call FileChannel.map() as follows:
File f = ... RandomAccessFile raf = new RandomAccessFile(f, "rw"); FileChannel fc = raf.getChannel(); ByteBuffer fileArea = fc.map(MapMode.READ_WRITE, offset, len);
Now, you can essentially use the get/put methods of fileArea just as you would with any ByteBuffer.
Instead of MapMode.READ_WRITE, two other mapping modes may be provided: MapMode.READ_ONLY and MapMode.PRIVATE. A read only mapping is self-explanatory; a private mapping is writable, but writes are reflected only in that MappedByteBuffer's contents (and not written to the file). If a writable mapping is requested (including a private one!), then the underlying means by which the file was opened must also support this (so e.g. you won't get a writable mapping from a channel opened via a FileInputStream!).
Characteristics of mapped ByteBuffers
Here are some other characteristics of mapped buffers that you should consider (these statements are true under Windows; I welcome feedback about other operating systems):
1. Windows actually provides a facility for mappings to be
made consistent across processes (by using the same handle returned by
CreateFileMapping from the different processes),
but Java provides no access to this facility. I imagine that the designers
judged that this facility is not necessarily available on other OSs and
probably rarely needed.
Written by Neil Coffey. Copyright © Javamex UK 2012. All rights reserved.