1、什么是内存映射文件java
内存映射文件,是由一个文件到一块内存的映射,能够理解为将一个文件映射到进程地址,而后能够经过操做内存来访问文件数据。说白了就是使用虚拟内存将磁盘的文件数据加载到虚拟内存的内存页,而后就能够直接操做内存页数据。缓存
咱们读写一个文件使用read()和write()方法,这两个方法是调用系统底层接口来传输数据,由于内核空间的文件页和用户空间的缓冲区没有一一对应,因此读写数据时会在内核空间和用户空间之间进行数据拷贝,在操做大量文件数据时会致使性能很低,使用内存映射文件能够很是高效的操做大量文件数据。app
经过内存映射机制操做文件比使用常规方法和使用FileChannel读写高效的多。dom
内存映射文件使用文件系统创建从用户空间到可用文件系统页的虚拟内存映射,这样作有如下好处:性能
1.用户进程把文件数据当内存数据,无需调用read()或write()大数据
2.当用户进程接触到映射内存空间,会自动产生页错误,从而将文件数据从磁盘读到内存;若用户空间进程修改了内存页数据,相关页会自动标记并刷新到磁盘,文件被更新操作系统
3.操做系统的虚拟内存对内存页进行高速缓存,自动根据系统负载进行内存管理code
4.用户空间和内核空间的数据老是一一对应,无需执行缓冲区拷贝接口
5.大数据的文件使用映射,无需消耗大量内存便可进行数据拷贝进程
2、如何建立内存映射文件
RandomAccessFile raf = new RandomAccessFile("test.txt", "rw"); FileChannel fc = raf.getChannel(); //将test.txt文件全部数据映射到虚拟内存,并只读 MappedByteBuffer mbuff = fc.map(MapMode.READ_ONLY, 0, fc.size());
映射文件的范围不该超过文件的实际大小,不然文件的大小会被增大到指定的大小
//实际文件只有10个字节,执行下面代码后,文件内容变为10000个字节 MappedByteBuffer mbuff = fc.map(MapMode.READ_WRITE, 0, 10000);
第一个参数MapMode是个三个值:
1. MapMode.READ_ONLY:只读,若FileChannel不可读,抛出NonReadableChannelException
2. MapMode.READ_WRITE:可读写,若FileChannel不可写,抛出NonWritableChannelException
3. MapMode.PRIVATE:建立一个写时拷贝的映射,修改映射内存页的数据只对MappedByteBuffer可视
3、MappedByteBuffer API
MappedByteBuffer是ByteBuffer的子类,因此可被通道读写。MappedByteBuffer提供的方法:
1. load():加载整个文件到内存
2. isLoaded():判断文件数据是否所有加载到了内存
3. force():将缓冲区的更改刷新到磁盘
4、通道到通道传输
将文件数据从一个通道传输到另外一个通道,FileChannel提供下面2个高效方法:
1. transferTo(long position, long count, WritableByteChannel target):传输到哪一个可写通道
2. transferFrom(ReadableByteChannel src, long position, long count):从哪一个可读通道传输过来
通道到通道传输数据使用上面2个方法不须要使用中间缓冲区。只有FileChannel有以上方法,因此Channel-to-Channel中必须有一个是FileChannel。
对于传输大量数据,以上2个方法的效率是很是高的。
//获取test0.txt文件的通道句柄 RandomAccessFile raf0 = new RandomAccessFile("test0.txt", "r"); FileChannel fc0 = raf0.getChannel(); //获取test1.txt文件的通道句柄 RandomAccessFile raf1 = new RandomAccessFile("test1.txt", "rw"); FileChannel fc1 = raf1.getChannel(); //将test0.txt传输到test1.txt fc0.transferTo(0, fc0.size(), fc1); //强制刷新数据到磁盘 fc0.force(true); //关闭通道 raf1.close(); raf0.close();