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. coolSQL安装与使用

    由于笔者最近支援其他项目,所使用的数据库为informix 所以安装一个coolSQL客户端方便些,当然命令行方式也可以,但是感觉不太友好,下面把安装与简单使用过程分享给大家. 一.下载coolSQL ...

  2. AngularJS_简介、特性及基本使用_及其工作原理

    转自:angularJS 的工作原理 转自:通过<script>标签引入到 HTML 中,那么此时 Angular 就做为一个普通的 DOM 节点等待浏览器解析 当浏览器解析到这个节点时, ...

  3. 7、vue-awesome-swiper页面跳转

    <template> <swiper :options='swiperOption' ref="mySwiper" class='swiper-container ...

  4. gvim 技巧

    1.对齐 很多时候想对齐括号和“=”号,行数很多的时候就是体力活了.使用3条命令就可以完成对齐 :set ts=16                    ##将tab设置为16 :%s/(/\t(/ ...

  5. python函数详解

    ''' 函数:是一段可以重复调用的代码,通过输入的参数,返回对应的结果 名字绑定的机制,把实际参数的值与形式参数的值绑定到一起 1.函数调用的时候,实际参数的值的顺序与形式参数的顺序一一对应 2.当在 ...

  6. python全栈开发 * css 选择器 浮动 * 180808

    css 选择器 一.基本选择器 1.标签选择器 标签选择器可以选中所有的标签元素,比如div,ul,li ,p等等,不管标签藏的多深,都能选中,选中的是所有的,而不是某一个,所以说 "共性& ...

  7. ALM 中查看某个 test 的更改 history 历史

    ALM 中要查看某个 test 更改历史, 需要下面两个表: AUDIT_LOG and AUDIT_PROPERTIES ------- Get Test modification history ...

  8. ie清理缓存

    说废话,直接上图. 1.打开浏览器 2.工具--->Internet选项 3.常规--->设置 4.Internet临时文件--->查看文件 5.将缓存文件夹中内容全部删除

  9. Java 线程池比较

    小结: 1. 高级面试题总结—线程池还能这么玩? - 这个时代,作为程序员可能要学习小程序 - CSDN博客https://blog.csdn.net/androidstarjack/article/ ...

  10. subline text3 安装 rem装换工具

    CSSREM 一个CSS的px值转rem值的Sublime Text 3自动完成插件. 插件效果如下: 安装 下载本项目,比如:git clone https://github.com/flashli ...