FileDocCategorySizeDatePackage
MapFile.javaAPI DocExample3892Mon May 20 00:24:28 BST 2002com.ronsoft.books.nio.channels

MapFile.java

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