1.  在JAVA传统的IO系统中,读取磁盘文件数据的过程如下:

以FileInputStream类为例,该类有一个read(byte b[])方法,byte b[]是我们要存储读取到用户空间的缓冲区。参看read(byte b[])方法的源码,可知,它会在内部再调用readBytes(b, 0, b.length)方法,而且readBytes(b, 0, b.length)方法是一个native方法(即本地方法),最终通过这个本地方法来发起一次系统调用,即调用系统内核的read()方法,内核从磁盘读取数据到内核缓冲区,这个过程由磁盘控制器通过DMA操作将数据从磁盘读取取内核缓冲区,此过程不依赖于CPU。然后用户进程再将数据从内核缓冲区拷贝到用户空间缓冲区。用户进程再从用户空间缓冲区中读取数据。因为用户进程是不可以直接访问硬件的。所以需要通过内核来充当中间人的作用来实现文件的读取。整个过程如下图所示:

2.  自从JAVA 1.4以后,JAVA在NIO在引入了文件通道的概念,在API中有提供了一个FileChannel类。该类与传统的IO流进行关联。可以由FileInputStream或FileOutputStream获取该文件通道,我们可以通过通道对文件进行读写操作。

3.JAVA NIO中还引入了文件内存映射的概念:现代操作系统大都支持虚拟内存映射,这样,我们可以把内核空间地址与用户空间的虚拟地址映射到同一个物理地址,这样,DMA 硬件(只能访问物理内存地址)就可以填充对内核与用户空间进程同时可见的缓冲区了。如下图所示:

这样做的好处是,我们在读取磁盘文件时,再也不用通过内核缓冲区到用户进程缓冲区的来回拷贝操作了。操作系统会通过一些页面调度算法来将磁盘文件载入对分页区进行高速缓存的物理内存。我们就可以通过映射后物理内存来读取磁盘文件了。

4.  下面我们通过三种不同方式文件拷贝的案例来验证文件通道及文件内存映射在IO系统中的作用。测试环境为windows 32位系统和JDK1.6。代码中使用的测试文件movie.avi为一个123MB的视频文件。代码如下:

package cn.com.hbust.nio.file; 

import java.io.File; 

import java.io.FileInputStream; 

import java.io.FileOutputStream; 

import java.nio.MappedByteBuffer; 

import java.nio.channels.FileChannel; 

public class FileCopyTest { 

    public  static  void main(String[] args) throws Exception { 

       String sourcePath = "F:\\mywork\\javademo\\dir1\\movie.avi"; 

       String destPath1 = "F:\\mywork\\javademo\\dir2\\movie1.avi"; 

       String destPath2 = "F:\\mywork\\javademo\\dir2\\movie2.avi"; 

       String destPath3 = "F:\\mywork\\javademo\\dir2\\movie3.avi"; 

       long t1 = System.currentTimeMillis(); 

       traditionalCopy(sourcePath,destPath1); 

       long t2 = System.currentTimeMillis(); 

       System.out.println("传统IO方法实现文件拷贝耗时:" + (t2-t1) + "ms"); 

       nioCopy(sourcePath,destPath2); 

       long t3 = System.currentTimeMillis(); 

       System.out.println("利用NIO文件通道方法实现文件拷贝耗时:" + (t3-t2) + "ms"); 

       nioCopy2(sourcePath,destPath3); 

       long t4 = System.currentTimeMillis(); 

       System.out.println("利用NIO文件内存映射及文件通道实现文件拷贝耗时:" + (t4-t3) + "ms"); 

    } 

    private  static  void nioCopy2(String sourcePath, String destPath) throws Exception { 

       File source = new File(sourcePath); 

       File dest = new File(destPath); 

       if(!dest.exists()) { 

           dest.createNewFile(); 

       } 

       FileInputStream fis = new FileInputStream(source); 

       FileOutputStream fos = new FileOutputStream(dest); 

       FileChannel sourceCh = fis.getChannel(); 

       FileChannel destCh = fos.getChannel(); 

       MappedByteBuffer mbb = sourceCh.map(FileChannel.MapMode.READ_ONLY, 0, sourceCh.size()); 

       destCh.write(mbb); 

       sourceCh.close(); 

       destCh.close(); 

    } 

    private  static  void traditionalCopy(String sourcePath, String destPath) throws Exception{ 

       File source = new File(sourcePath); 

       File dest = new File(destPath); 

       if(!dest.exists()) { 

           dest.createNewFile(); 

       } 

       FileInputStream fis = new FileInputStream(source); 

       FileOutputStream fos = new FileOutputStream(dest); 

       byte [] buf = newbyte [512]; 

       int len = 0; 

       while((len = fis.read(buf)) != -1) { 

           fos.write(buf, 0, len); 

       } 

       fis.close(); 

       fos.close(); 

    } 

    private  static  void nioCopy(String sourcePath, String destPath) throws Exception{ 

       File source = new File(sourcePath); 

       File dest = new File(destPath); 

       if(!dest.exists()) { 

           dest.createNewFile(); 

       } 

       FileInputStream fis = new FileInputStream(source); 

       FileOutputStream fos = new FileOutputStream(dest); 

       FileChannel sourceCh = fis.getChannel(); 

       FileChannel destCh = fos.getChannel(); 

       destCh.transferFrom(sourceCh, 0, sourceCh.size()); 

       sourceCh.close(); 

       destCh.close(); 

    } 

}

  

每执行完一次拷贝之后,将F:\mywork\javademo\dir2\目录中的内容删除掉,重复执行8次。观察测试结果如下:时间单位为ms(毫秒)

由上表可知,传统IO方式平均拷贝完成时间约为1968ms,NIO文件通道方式平均拷贝完成时间约为1672ms,文件内存映射及文件通道方式平均拷贝完成时间约为1418ms。

转载自http://www.open-open.com/lib/view/open1413518521372.html

Java IO和Java NIO 和通道 在文件拷贝上的性能差异分析的更多相关文章

  1. Java IO和Java NIO在文件拷贝上的性能差异分析

    1.  在JAVA传统的IO系统中,读取磁盘文件数据的过程如下: 以FileInputStream类为例,该类有一个read(byte b[])方法,byte b[]是我们要存储读取到用户空间的缓冲区 ...

  2. hive运行query语句时提示错误:org.apache.hadoop.ipc.RemoteException: java.io.IOException: java.io.IOException:

    hive> select product_id, track_time from trackinfo limit 5; Total MapReduce jobs = 1 Launching Jo ...

  3. java.io.OutputStream & java.io.FileOutputStream

    java.io.OutputStream & java.io.FileOutputStream 1.Java.io.OutputStream(字节输出流) 字节输出流,这是一个抽象类,是表示输 ...

  4. hadoop报错:java.io.IOException(java.net.ConnectException: Call From xxx/xxx to xxx:10020 failed on connection exception: java.net.ConnectException: 拒绝连接

    任务一直报错 现象比较奇怪,部分任务可以正常跑,部分问题报错 报错信息如下: Ended Job = job_1527476268558_132947 with exception 'java.io. ...

  5. java.io.IOException: java.sql.SQLException: ORA-01502: index 'BTO.PK_xxxxx' or partition of such index is in unusable state

    最近由于数据库的全备出问题了,所以一直在观察. 刚好发现很多不需要的数据,就删了几百个G的数据吧. 今天突然就报这个问题. java.io.IOException: java.sql.SQLExcep ...

  6. ERROR tool.ImportTool: Import failed: java.io.IOException: java.lang.ClassNotFoundException: org.apache.hadoop.hive.conf.HiveConf

    sqoop从mysql导入到hive报错: 18/08/22 13:30:53 ERROR tool.ImportTool: Import failed: java.io.IOException: j ...

  7. sqoop mysql--->hive 报错 (ERROR tool.ImportTool: Import failed: java.io.IOException: java.lang.ClassNotFoundException: org.apache.hadoop.hive.conf.HiveConf)

    ERROR tool.ImportTool: Import failed: java.io.IOException: java.lang.ClassNotFoundException: org.apa ...

  8. Hive报错 Failed with exception java.io.IOException:java.lang.IllegalArgumentException: java.net.URISyntaxException: Relative path in absolute URI: ${system:user.name%7D

    报错信息如下 Failed with exception java.io.IOException:java.lang.IllegalArgumentException: java.net.URISyn ...

  9. Intellij IDEA报错:Could not save application settings: java.io.IOException: java.lang.AssertionError: Unexpected content storage modificat

    Question: i have a message saying "Could not save application settings: java.io.IOException: ja ...

随机推荐

  1. C# 数据为空,不能对NULL调用此方法或属性的解决办法

    在运行C#项目时,报出了以下错误,错误原因是数据库中的值为null时,查询时会触发该错误提示 部分源代码如下: public List<Student> findData2() { ; / ...

  2. 省市区地址三级联动jQuery插件Distpicker使用

    插件下载地址 http://www.jq22.com/jquery-info8054 效果如下: 使用: 1.引入js <script src="http://www.jq22.com ...

  3. Java菜鸟浅谈OCR

    什么是OCR? 粗暴点说就是图片文本识别!正规点的说法就是:(Optical Character Recognition,光学电子识别) 最近公司开展新项目,考虑到实名认证这方面,然后还要上传身份证正 ...

  4. Python数据分析基础教程

    Python数据分析基础教程(第2版)(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/1_FsReTBCaL_PzKhM0o6l0g 提取码:nkhw 复制这段内容后 ...

  5. 16重新安装HA0.63

    2018-02-24 14:17:46 https://home-assistant.io/docs/installation/raspberry-pi/首先安装2017-11-29-raspbian ...

  6. BZOJ5254 : [Fjwc2018]红绿灯

    显然所有询问都要经过至少$\sum d$,只需要考虑除了$\sum d$之外的等待红灯的时间. 将所有询问的时间模$g+r$,并按时间用set维护. 那么对于每个红灯,在set中可以找出$1$到$2$ ...

  7. goroutine 和线程的区别

    好久没写点儿啥了,强行更新一下. 1,从使用上讲 1,goroutine 比线程更轻量级,可以创建十万.百万不用担心资源问题. 2,goroutine 和 chan 搭配使用,实现多线程.高并发 实现 ...

  8. 在Windows上安装Nexus 3.2.0-01

      在Windows上安装Nexus 环境: Windows 7 apache-maven-3.3.9 JDK 1.8 下载Nexus: https://sonatype-download.globa ...

  9. IDEA_教你十分钟下载并破解IntelliJ IDEA(2017)(转)

    之前都是用myeclipse,但是最近发现看的很多教学视频都是使用 IntelliJ IDEA,于是决定换个软件开始新的学习征程! 下面讲讲我是如何在十分钟之内安装并破解该软件. 1.首先,我找到了  ...

  10. [LeetCode] Design HashSet 设计HashSet

    Design a HashSet without using any built-in hash table libraries. To be specific, your design should ...