package com.ronsoft.books.nio.channels;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.io.File;
import java.io.RandomAccessFile;
/**
* Test behavior of Memory mapped buffer types. Create a file, write
* some data to it, then create three different types of mappings
* to it. Observe the effects of changes through the buffer APIs
* and updating the file directly. The data spans page boundaries
* to illustrate the page-oriented nature of Copy-On-Write mappings.
*
* Created: April 2002
* @author Ron Hitchens (ron@ronsoft.com)
* @version $Id: MapFile.java,v 1.3 2002/05/20 07:24:29 ron Exp $
*/
public class MapFile
{
public static void main (String [] argv)
throws Exception
{
// create a temp file and get a channel connected to it
File tempFile = File.createTempFile ("mmaptest", null);
RandomAccessFile file = new RandomAccessFile (tempFile, "rw");
FileChannel channel = file.getChannel();
ByteBuffer temp = ByteBuffer.allocate (100);
// put something in the file, starting at location 0
temp.put ("This is the file content".getBytes());
temp.flip();
channel.write (temp, 0);
// Put something else in the file, starting at location 8192
// 8192 is 8k, almost certainly a different memory/FS page.
// This may cause a file hole, depending on the
// filesystem page size.
temp.clear();
temp.put ("This is more file content".getBytes());
temp.flip();
channel.write (temp, 8192);
// create three types of mappings to the same file
MappedByteBuffer ro = channel.map (
FileChannel.MapMode.READ_ONLY, 0, channel.size());
MappedByteBuffer rw = channel.map (
FileChannel.MapMode.READ_WRITE, 0, channel.size());
MappedByteBuffer cow = channel.map (
FileChannel.MapMode.PRIVATE, 0, channel.size());
// The buffer states before any modifications
System.out.println ("Begin");
showBuffers (ro, rw, cow);
// modify the Copy-On-Write buffer
cow.position (8);
cow.put ("COW".getBytes());
System.out.println ("Change to COW buffer");
showBuffers (ro, rw, cow);
// Modify the Read/Write buffer
rw.position (9);
rw.put (" R/W ".getBytes());
rw.position (8194);
rw.put (" R/W ".getBytes());
rw.force();
System.out.println ("Change to R/W buffer");
showBuffers (ro, rw, cow);
// Write to the file through the channel, hit both pages
temp.clear();
temp.put ("Channel write ".getBytes());
temp.flip();
channel.write (temp, 0);
temp.rewind();
channel.write (temp, 8202);
System.out.println ("Write on channel");
showBuffers (ro, rw, cow);
// modify the Copy-On-Write buffer again
cow.position (8207);
cow.put (" COW2 ".getBytes());
System.out.println ("Second change to COW buffer");
showBuffers (ro, rw, cow);
// Modify the Read/Write buffer
rw.position (0);
rw.put (" R/W2 ".getBytes());
rw.position (8210);
rw.put (" R/W2 ".getBytes());
rw.force();
System.out.println ("Second change to R/W buffer");
showBuffers (ro, rw, cow);
// cleanup
channel.close();
file.close();
tempFile.delete();
}
// show the current content of the three buffers
public static void showBuffers (ByteBuffer ro, ByteBuffer rw,
ByteBuffer cow)
throws Exception
{
dumpBuffer ("R/O", ro);
dumpBuffer ("R/W", rw);
dumpBuffer ("COW", cow);
System.out.println ("");
}
// dump buffer content, counting and skipping nulls
public static void dumpBuffer (String prefix, ByteBuffer buffer)
throws Exception
{
System.out.print (prefix + ": '");
int nulls = 0;
int limit = buffer.limit();
for (int i = 0; i < limit; i++) {
char c = (char) buffer.get (i);
if (c == '\u0000') {
nulls++;
continue;
}
if (nulls != 0) {
System.out.print ("|[" + nulls
+ " nulls]|");
nulls = 0;
}
System.out.print (c);
}
System.out.println ("'");
}
}
|