java中io与nio复制文件性能对比
2019獨角獸企業重金招聘Python工程師標準>>>
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在引入了文件通道的概念,和傳統IO最大的區別是:傳統IO是基于Byte(字節)和Stream(流)的,而NIO是基于Buffer(緩沖)、Channel(通道)在API中有提供了一個FileChannel類和Selector(選擇器)的,該類與傳統的IO流進行關聯。可以由FileInputStream或FileOutputStream獲取該文件通道,我們可以通過通道對文件進行讀寫操作。
3.JAVA NIO中還引入了文件內存映射的概念:現代操作系統大都支持虛擬內存映射,這樣,我們可以把內核空間地址與用戶空間的虛擬地址映射到同一個物理地址,這樣,DMA 硬件(只能訪問物理內存地址)就可以填充對內核與用戶空間進程同時可見的緩沖區了。如下圖所示:
下面就看下使用IO,BufferedIO和NIO分別實現的文件復制耗時比較:11兆音頻文件
傳統IO方法實現文件拷貝耗時:21ms
利用NIO文件通道方法實現文件拷貝耗時:16ms
利用NIO文件內存映射及文件通道實現文件拷貝耗時:7ms
利用FileUtils文件拷貝工具類耗時:53ms
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();?
? ??
? ? ?}?
? ??
?}?
轉載于:https://my.oschina.net/u/1054538/blog/770067
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的java中io与nio复制文件性能对比的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Chrome一直提示“adobe fla
- 下一篇: SCM-SVN集成服务器