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. Java.io下的方法是对磁盘上的文件进行磁盘操作

    File类(java.io.*)可表示一个文件,也有可能是一个目录(在JAVA中文件和目录都属于这个类中,而且区分不是非常的明显). Java.io下的方法是对磁盘上的文件进行磁盘操作,但是无法读取文 ...

  3. java.io.IOException: java.io.FileNotFoundException: /tmp/tomcat.2457258178644046891.8080/work/Tomcat/localhost/innovate-admin/C:/up/154884318438733213952/sys-error.log (没有那个文件或目录)

    环境: Ubuntu18 vue+elementUI 实现文件的上传 报错信息: MultipartFile.transferTo(dest) 报 FileNotFoundException java ...

  4. java.io.OutputStream & java.io.FileOutputStream

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

  5. 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 ...

  6. 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 ...

  7. 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 ...

  8. 缓冲字符流 java.io.BufferedWriter ,java.io.BufferedReader,缓冲字符输出流:PrintWriter

    package seday07; import java.io.IOException;import java.io.PrintWriter; /*** @author xingsir * 缓冲字符流 ...

  9. 转换流读写操作 java.io.OutputStreamWriter ,java.io.InputStreamReader

    package seday07; import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStr ...

随机推荐

  1. MySql 5.6 查询日志

    记录所有查询的方法 打开My.ini 在 [mysqld]下面写 general_log= ON; log_output= TABLE; 然后保存重启mysql 最后在mysql库下 general_ ...

  2. iOS tableview 优化总结

    根据网络上的优化方法进行了总括.并未仔细进行语言组织.正在这些优化方法进行学习,见另一篇文章 提高app流畅度 1.cell子控件创建写在 initWithStyle:reuseIdentifier ...

  3. Lync激活用户遇到ConstraintViolationNoLeadingOrTrailingWhitespace错误

    启用用户的时候出现错误ConstraintViolationNoLeadingOrTrailingWhitespace,如下图 解决方案:域控中,该用户的名字最后多出了个空格,批量生成域用户的脚本问题 ...

  4. 第三百六十天 how can I 坚持

    看了两集linux视频,有点懵啊,下班还想走去天安门,想啥呢,太远了. 居住证没法办,哎,要入职两年. 考研要是也不能考,这一年也太.. 点不会那么背吧. 好像没啥了,睡觉.

  5. ApplicationIdle

    ApplicationIdle 不忙的时候调用此事件 ::Fmx::Forms::Application->OnIdle = ApplicationIdle; void __fastcall T ...

  6. Leveldb Advanced

    [Slice] The return value of the it->key() and it->value() is a simple structure that contains ...

  7. SpriteParticle II

    [SpriteParticle II] 1.Randomizing the Starting Position 2.Setting the Initial Angle 3.Setting a Part ...

  8. nyoj 119 士兵杀敌(三)(RMQ)

    士兵杀敌(三) 时间限制:2000 ms  |  内存限制:65535 KB 难度:5   描述 南将军统率着N个士兵,士兵分别编号为1~N,南将军经常爱拿某一段编号内杀敌数最高的人与杀敌数最低的人进 ...

  9. python 前向引用

    即函数调用在函数定义之前 可以这样 def bbb(): print('this is b') aaa() def aaa(): print('this is a') bbb() ---------& ...

  10. URAL 2069 Hard Rock (最短路)

    题意:给定 n + m 个街道,问你从左上角走到右下角的所有路的权值最小的中的最大的. 析:我们只要考虑几种情况就好了,先走行再走列和先走列再走行差不多.要么是先横着,再竖着,要么是先横再竖再横,要么 ...