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在文件拷貝上的性能差別分析 java

2.  自從JAVA 1.4之後,JAVA在NIO在引入了文件通道的概念,和傳統IO最大的區別是:傳統IO是基於Byte(字節)和Stream(流)的,而NIO是基於Buffer(緩衝)、Channel(通道)在API中有提供了一個FileChannel類和Selector(選擇器)的,該類與傳統的IO流進行關聯。能夠由FileInputStream或FileOutputStream獲取該文件通道,咱們能夠經過通道對文件進行讀寫操做。

3.JAVA NIO中還引入了文件內存映射的概念:現代操做系統大都支持虛擬內存映射,這樣,咱們能夠把內核空間地址與用戶空間的虛擬地址映射到同一個物理地址,這樣,DMA 硬件(只能訪問物理內存地址)就能夠填充對內核與用戶空間進程同時可見的緩衝區了。以下圖所示:

 Java IO和Java NIO在文件拷貝上的性能差別分析

下面就看下使用IO,BufferedIO和NIO分別實現的文件複製耗時比較:11兆音頻文件apache

傳統IO方法實現文件拷貝耗時:21ms
利用NIO文件通道方法實現文件拷貝耗時:16ms
利用NIO文件內存映射及文件通道實現文件拷貝耗時:7ms
利用FileUtils文件拷貝工具類耗時:53msapp

package com.maystar.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;工具

import org.apache.commons.io.FileUtils;性能

public class FileCopyTest { 
     
      public  static  void main(String[] args) throws Exception { 
     
         String sourcePath = "F:\\glzmv.mp3"; 
     
         String destPath1 = "F:\\glzmvCopy1.mp3"; 
     
         String destPath2 = "F:\\glzmvCopy2.mp3"; 
     
         String destPath3 = "F:\\glzmvCopy3.mp3"; 
         
         String destPath4 = "F:\\glzmvCopy4.mp3"; 
         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"); 
         
         nioCopy3(sourcePath,destPath4); 
         long t5 = System.currentTimeMillis(); 
         System.out.println("利用FileUtils文件拷貝耗時:" + (t5-t4) + "ms"); 
      } 
      private  static  void nioCopy3(String sourcePath, String destPath) throws Exception { 
             
          File source = new File(sourcePath); 
      
          File dest = new File(destPath); 
      
      
         FileUtils.copyFile(source, dest);//查看源碼commons-io-2.4也使用的是nio操做,實現相似nioCopy操做,可是爲何效率比nioCopy要低,緣由是在FileUtils.copyFile執行doCopyFile完成調用IOUtils工具類關閉流操做,根據不一樣類型的流調用對應的構造方法。
      
       } 
      
      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 = new byte [fis.available()]; 
    
        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(); 
    
     } 
    
 } spa

相關文章
相關標籤/搜索