MappedByteBuffer是java nio引入的文件内存映射方案,读写性能极高。NIO最主要的就是实现了对异步操作的支持。其中一种通过把一个套接字通道(SocketChannel) 注册到一个选择器(Selector)中,不时调用后者的选择(select)方法就能返回满足的选择键(SelectionKey),键中包含了 SOCKET事件信息。这就是select模型。
    SocketChannel的读写是通过一个类叫ByteBuffer(java.nio.ByteBuffer)来操作的.这个类本身的设计是不错的, 比直接操作byte[]方便多了. ByteBuffer有两种模式:直接/间接.间接模式最典型(也只有这么一种)的就是HeapByteBuffer,即操作堆内存 (byte[]).但是内存毕竟有限,如果我要发送一个1G的文件怎么办?不可能真的去分配1G的内存.这时就必须使用"直接"模式,即 MappedByteBuffer,文件映射.
     先中断一下,谈谈操作系统的内存管理.一般操作系统的内存分两部分:物理内存;虚拟内存.虚拟内存一般使用的是页面映像文件,即硬盘中的某个(某些)特殊 的文件.操作系统负责页面文件内容的读写,这个过程叫"页面中断/切换". MappedByteBuffer也是类似的,你可以把整个文件(不管文件有多大)看成是一个ByteBuffer.MappedByteBuffer 只是一种特殊的 ByteBuffer ,即是ByteBuffer的子类。 MappedByteBuffer 将文件直接映射到内存(这里的内存指的是虚拟内存,并不是物理内存)。通常,可以映射整个文件,如果文件比较大的话可以分段进行映射,只要指定文件的那个 部分就可以。

三种方式:
              FileChannel提供了map方法来把文件影射为内存映像文件: MappedByteBuffer map(int mode,long position,long size); 可以把文件的从position开始的size大小的区域映射为内存映像文件,mode指出了 可访问该内存映像文件的方式:READ_ONLY,READ_WRITE,PRIVATE.                     
a. READ_ONLY,(只读): 试图修改得到的缓冲区将导致抛出 ReadOnlyBufferException.(MapMode.READ_ONLY)
 b. READ_WRITE(读/写): 对得到的缓冲区的更改最终将传播到文件;该更改对映射到同一文件的其他程序不一定是可见的。 (MapMode.READ_WRITE)
c. PRIVATE(专用): 对得到的缓冲区的更改不会传播到文件,并且该更改对映射到同一文件的其他程序也不是可见的;相反,会创建缓冲区已修改部分的专用副本。 (MapMode.PRIVATE)

三个方法:

a. fore();缓冲区是READ_WRITE模式下,此方法对缓冲区内容的修改强行写入文件
b. load()将缓冲区的内容载入内存,并返回该缓冲区的引用
c. isLoaded()如果缓冲区的内容在物理内存中,则返回真,否则返回假

三个特性:

调用信道的map()方法后,即可将文件的某一部分或全部映射到内存中,映射内存缓冲区是个直接缓冲区,继承自ByteBuffer,但相对于ByteBuffer,它有更多的优点:

a. 读取快
b. 写入快
c. 随时随地写入

下面来看代码:
package com.zero.nio.test;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class Test implements INIOTest{
public void copyFileMapped(String oldPath,String newPath)  throws IOException{
long length=0;
RandomAccessFile raf=new RandomAccessFile(oldPath , "r");
FileChannel fcr=raf.getChannel();
length=fcr.size();
//返回要读取文件的映射内存区块
MappedByteBuffer mbb=fcr.map(FileChannel.MapMode.READ_ONLY, 0, length);
ByteBuffer buffer=mbb.get(new byte[(int)length]);

//要写入的文件
RandomAccessFile raw=new RandomAccessFile(newPath, "rw");
FileChannel fcw=raw.getChannel();
MappedByteBuffer mbbw=fcw.map(FileChannel.MapMode.READ_WRITE, 0, length);
for(int i=0;i<length;i++){
mbbw.put(i,buffer.get(i));
}
fcw.close();
fcr.close();
raf.close();
raw.close();
/**
* MappedByteBuffer是java平台共享内存的实现,把硬盘虚拟为内存,
* 主要用于进程间共享数据,所以在进程没有退出前文件是不允许删除的。 
* 一个映射的字节缓冲区和文件映射,它代表仍然有效,直到缓冲本身是垃圾收集。
*/
raf=null;
raw=null;
System.gc();
try {
//等待垃圾回收
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}

}
public void copyFileNIO(String oldPath,String newPath) throws IOException{
FileInputStream fis=new FileInputStream(oldPath);
FileOutputStream fos=new FileOutputStream(newPath);
//获取输入输出通道
FileChannel fcin=fis.getChannel();
FileChannel fout=fos.getChannel();
//创建缓冲区
ByteBuffer buffer=ByteBuffer.allocate(1024);
while(true){
//clear方法重设缓冲区,使它可以接受读入的数据  
buffer.clear();
int len=fcin.read(buffer);
if(len==-1){

break;
}
//写模式转换成读模式。该限制设置为当前的位置然后位置设置为零。如果标记定义然后丢弃。
//flip方法让缓冲区可以将新读入的数据写入另一个通道  
buffer.flip();
fout.write(buffer);
}
fcin.close();
fout.close();
}

public void copyFile(String oldPath,String newPath) throws IOException{
FileInputStream fis=new FileInputStream(oldPath);
FileOutputStream fos=new FileOutputStream(newPath);

BufferedInputStream bis=new BufferedInputStream(fis);
BufferedOutputStream bos=new BufferedOutputStream(fos);
byte[] buffer=new byte[1024];

int len=0;
while((len=bis.read(buffer))!=-1){
bos.write(buffer,0,buffer.length);
}
        bis.close();
bos.close();
}
public static void main(String agrs[]){

INIOTest test1=(INIOTest)TestHandler.newInstance(new Test());
try {
test1.copyFileMapped("D:\\20140415.txt","D:\\test.txt");
test1.copyFileNIO("D:\\20140415.txt","D:\\test1.txt");
test1.copyFile("D:\\20140415.txt","D:\\test2.txt");
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}

}

}

可以看出速度有了很大的提升。MappedByteBuffer的确快,但也存在一些问题,主要就是内存占用和文件关闭等不确定问题。被MappedByteBuffer打开的文件只有在垃圾收集时才会被关闭,而这个点是不确定的。在javadoc里是这么说的:

A mapped byte buffer and the file mapping that it represents remain valid until the buffer itself is garbage-collected.

这里提供一种解决方案:

AccessController.doPrivileged(new PrivilegedAction() {  public Object run() {    try {      Method getCleanerMethod = buffer.getClass().getMethod("cleaner", new Class[0]);      getCleanerMethod.setAccessible(true);      sun.misc.Cleaner cleaner = (sun.misc.Cleaner)       getCleanerMethod.invoke(byteBuffer, new Object[0]);      cleaner.clean();    } catch (Exception e) {      e.printStackTrace();    }    return null;  }});

java nio MappedByteBuffer 文件映射相关推荐

  1. java nio拷贝文件_Java 7 – NIO文件革命

    java nio拷贝文件 Java 7("项目代币")已于去年7月问世. 此版本中的新增功能很有用,例如,尝试资源-从try块中自动处理可关闭的资源,switch语句中的字符串,用 ...

  2. 实验六 : java nio 写文件速度

    java nio 写文件的速度与io 写文件速度相当, 例子3_3 package experiment3_3; import java.io.FileNotFoundException; impor ...

  3. JAVA NIO之文件通道

    1.简介 通道是 Java NIO 的核心内容之一,在使用上,通道需和缓存类(ByteBuffer)配合完成读写等操作.与传统的流式 IO 中数据单向流动不同,通道中的数据可以双向流动.通道既可以读, ...

  4. Java NIO 读取文件、写入文件、读取写入混合

    前言 Java NIO(new/inputstream outputstream)使用通道.缓冲来操作流,所以要深刻理解这些概念,尤其是,缓冲中的数据结构(当前位置(position).限制(limi ...

  5. 惊!一文看懂Java NIO读写文件

    Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式.很多小伙伴可能和我一样,对于习惯了 ...

  6. JAVA实现资源文件映射

    后端服务启动后,未设置路径映射时,通过浏览器仅能访问项目路径下的资源文件.若想访问服务器其他磁盘的文件则需要做磁盘映射,具体使用方法如下: 1.具体实现 增加以下配置类,实现WebMvcConfigu ...

  7. java nio写文件nul_使用Java NIO编写高性能的服务器 文件下载

    从 JDK 1.4 开始,Java的标准库中就包含了NIO , 即所谓的"New IO".其中最重要的功能就是提供了"非阻塞"的IO,当然包括了Socket.N ...

  8. java大文件读写操作,java nio 之MappedByteBuffer,高效文件/内存映射

    http://langgufu.iteye.com/blog/2107023 java处理大文件,一般用BufferedReader,BufferedInputStream这类带缓冲的Io类,不过如果 ...

  9. 【JavaNIO的深入研究4】内存映射文件I/O,大文件读写操作,Java nio之MappedByteBuffer,高效文件/内存映射...

    内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件.有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问.这种解决办法能大大简化修改文件的代码. file ...

最新文章

  1. Linux设备驱动开发-linux驱动中的非阻塞访问方式
  2. Python字典get()方法的实际应用
  3. 6 volist双层数组_Javascript算法 — 数组排序
  4. 当启动vue项目安装依赖时报错
  5. c 远程登陆linux,Linux C/C++基础——Windows远程登录Linux
  6. 协方差矩阵、相关矩阵的详细说明
  7. ERP人力资源管理系统
  8. 三维空间数据建模——Smart3D的安装
  9. 网络安全实验5 证书应用和证书管理
  10. DC中保存ddc格式文件(亲测有效!)save the unmapped design in ddc format
  11. w10怎样关闭对计算机更改,W10电脑系统自动更新怎么关闭
  12. OpenLayers禁用鼠标双击放大事件
  13. Android 6.0 屏幕旋转
  14. poj1061青蛙的约会
  15. tcl/tk参考——列表操作lsearch
  16. 二叉树的自下而上、从右到左的层次遍历算法实现
  17. PX4飞行模式-多旋翼
  18. STM32——外部中断
  19. 第4章第1节:如何往幻灯片中插入指定行和列的表格 [PowerPoint精美幻灯片实战教程]
  20. 在Linux服务器上安装cmake遇到的小问题

热门文章

  1. 用verilog实现检测1的个数_[转]常用数字处理算法的Verilog实现
  2. catia v5r18 百度云_catia v5r18 64位免费版 附带安装教程
  3. 基于Java Web考生评分系统设计实现毕业设计源码071114
  4. 墨言教育:黄鹤楼1800年历史主题海报邀请展:传递历史文化积淀和新时代风采
  5. VBS 请求WebAPI接口_如何设计WEB API
  6. python切割、拼接图片
  7. 王者荣耀交流协会第6次Scrum立会
  8. Maven的学习总结
  9. 破解无线网络密码-BT3如何使用1
  10. 商用三维虚拟数字人如何制作