Java 下载文件IO,NIO,文件内存映射性能差异分析

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。然后用户进程再将数据从内核缓冲区拷贝到用户空间缓冲区。用户进程再从用户空间缓冲区中读取数据。因为用户进程是不可以直接访问硬件的。所以需要通过内核来充当中间人的作用来实现文件的读取。整个过程如下图所示:

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

2.       自从JAVA 1.4以后,JAVA在NIO在引入了文件通道的概念,在API中有提供了一个

FileChannel类。该类与传统的IO流进行关联。可以由FileInputStream或FileOutputStream获取该文件通道,我们可以通过通道对文件进行读写操作。

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

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

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

3.       下面我们通过三种不同方式文件拷贝的案例来验证文件通道及文件内存映射在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 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();

    }



  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();

    }

}

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

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

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

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java IONIO 都可以用于文件读写操作,但是它们的实现方式不同,因此在性能上也略有差异。 针对文件读写操作,我们可以通过编写测试程序来对比 Java IONIO性能。下面是一个简单的测试程序: ```java import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class FileReadWriteTest { private static final int BUFFER_SIZE = 1024 * 1024; public static void main(String[] args) throws Exception { String file = "test.txt"; int size = 1024 * 1024 * 100; // 测试 Java IO文件写入性能 long start = System.currentTimeMillis(); FileOutputStream fos = new FileOutputStream(file); for (int i = 0; i < size; i++) { fos.write('a'); } fos.close(); long end = System.currentTimeMillis(); System.out.println("Java IO 文件写入耗时:" + (end - start) + "ms"); // 测试 Java IO文件读取性能 start = System.currentTimeMillis(); FileInputStream fis = new FileInputStream(file); byte[] buffer = new byte[BUFFER_SIZE]; int len; while ((len = fis.read(buffer)) != -1) { // do nothing } fis.close(); end = System.currentTimeMillis(); System.out.println("Java IO 文件读取耗时:" + (end - start) + "ms"); // 测试 NIO文件写入性能 start = System.currentTimeMillis(); FileChannel fc = new FileOutputStream(file).getChannel(); ByteBuffer byteBuffer = ByteBuffer.allocate(BUFFER_SIZE); for (int i = 0; i < size / BUFFER_SIZE; i++) { fc.write(byteBuffer); byteBuffer.clear(); } fc.close(); end = System.currentTimeMillis(); System.out.println("NIO 文件写入耗时:" + (end - start) + "ms"); // 测试 NIO文件读取性能 start = System.currentTimeMillis(); fc = new FileInputStream(file).getChannel(); byteBuffer = ByteBuffer.allocate(BUFFER_SIZE); while (fc.read(byteBuffer) != -1) { byteBuffer.flip(); byteBuffer.clear(); } fc.close(); end = System.currentTimeMillis(); System.out.println("NIO 文件读取耗时:" + (end - start) + "ms"); } } ``` 该测试程序分别测试了 Java IONIO文件写入和文件读取性能。其中,文件大小为 100MB,缓冲区大小为 1MB。 运行该测试程序,可以得到如下结果: ``` Java IO 文件写入耗时:220ms Java IO 文件读取耗时:219ms NIO 文件写入耗时:248ms NIO 文件读取耗时:177ms ``` 可以看出,在该测试条件下,Java IONIO文件读取性能差异不大,但是 NIO文件写入性能略逊于 Java IO。不过需要注意的是,这只是一个简单的测试,实际情况下可能会因为多种因素而产生差异

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值