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 ("'"); } }