*概述 ---通过FileChannel的map(),可以使用directbuffer的方式读写文件内容,这里称之为内存映射. Open Declaration MappedByteBuffer ja...
*概述
---通过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之间的关系
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()是无效的
MappedByteBuffer示例2/**
* 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(" ");
}
}