*概述
---通过FileChannel的map(),可以使用directbuffer的方式读写文件内容,这里称之为内存映射.
Open Declaration MappedByteBuffer java.nio.channels.FileChannel.map(MapMode mode, long position, long size) throws IOException
*MappedByteBuffer
---优点
没有系统调用,节省了时间,这是使用directbuffer的好处,没有JVM和系统之间的复制操作.
---特殊的buffer,对应文件内容在虚拟内存中的一个区域,是direct buffer.所以创建需要的代价更大,适用于对大文件操作的情况.
---map()调用时的参数MapMode,它是FileChannel的静态内部类,定义对bufffer内容的执行方式
MapMode.READ_ONLY,只能对buffer进行读操作,否则抛出异常,NonWritableChannelException.
MapMode.READ_WRITE,可读可写,修改会写入文件.
MapMode.PRIVATE,可读可写,但是修改的内容不会写入文件,只是buffer自身的改变,称之为”copy on write”.
“copy on write”的好处,同一文件的多个buffer,可以共享同一片内存页.
注意,同一文件的MapMode.READ_ONLY和MapMode.READ_WRITE是公用同一个数组,但是MapMode.PRIVATE却是各自独立的.
*MappedByteBuffer的API
---load()
将buffer的内容,加载到物理内存中,目的是为了更快的操作.
但是这个方法受到很多因素的影响,如文件系统,JVM,系统内存等,总之慎用.
---force()
将buffer修改的内容,全部写入文件.只对MapMode.READ_WRITE有效
*示例一
---from java nio,说明了同一个文件的各种模式的MappedByteBuffer之间的关系
package nio.channel; import java.io.File; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; /** * 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. * * @author Ron Hitchens (ron@ronsoft.com) */ 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 8 KB, 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 ("'"); } }
*示例二
---说明同一文件的MapMode.PRIVATE的buffer之间是互补影响的,且force()是无效的
/** * Mar 27, 2011 by dzh */ package nio.channel; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; /** * @author dzh * */ public class MapFile1 { /** * @param args */ public static void main(String[] args) { try { File tempFile =File.createTempFile("tempFile", null); RandomAccessFile raf =new RandomAccessFile(tempFile,"rw"); FileChannel fc =raf.getChannel(); //initialize file's content ByteBuffer buffer =ByteBuffer.allocate(100); buffer.put("The whether has been bad these day in GuangZhou".getBytes()); buffer.flip(); fc.write(buffer); MappedByteBuffer mbb0 =fc.map(MapMode.PRIVATE, 0, fc.size()); MappedByteBuffer mbb1 =fc.map(MapMode.PRIVATE, 0, fc.size()); System.out.println("Change mbb0 buffer"); mbb0.position(4); mbb0.put("dzh".getBytes()); showBuffer("mbb0",mbb0); //The dzhther has been bad these day in GuangZhou showBuffer("mbb1",mbb1); //The whether has been bad these day in GuangZhou mbb0.force(); //no effect MappedByteBuffer content =fc.map(MapMode.PRIVATE, 0, fc.size()); showBuffer("file content", content); //The whether has been bad these day in GuangZhou raf.close(); tempFile.delete(); } catch (IOException e) { e.printStackTrace(); } } /** * 输出buffer的内容 * @param name * @param buffer */ private static void showBuffer(String name,MappedByteBuffer buffer){ System.out.println(name+":"); for(int i=0;i<buffer.limit();i++){ char c =(char) buffer.get(i); System.out.print(c); } System.out.println(" "); } }