天天看點

IO流不同方法copy檔案的效率分析

IO流copy檔案的幾種方法介紹

1、FileInputStream和FileOutputStream:檔案的讀寫一般是以位元組為機關的,前者從檔案中擷取位元組資料,後者将位元組資料寫入檔案。這種方式擷取的對象對于資料的讀寫是逐位元組的,稍後我們将測試其讀寫的速度。在讀寫的過程中我們可以這樣了解,read()方法檢視其底層可以發現是一個native方法,native方法連接配接了java和底層的C語言,IO流讀取到了資料,儲存在一個8位(一個位元組)的寄存器中,最簡單的檔案流就是對這個寄存器上的資料進行操作的,這也是為什麼這種方法是逐位元組讀寫的原因,這種方式在每次讀完一個位元組的的時候,就會産生溢出中斷,CPU再去響應中斷請求,這樣一來,其效率是很低下的,在讀大檔案的時候,這種方法就捉襟見肘了。

2、BufferedInputStream和BufferedOutputStream:緩沖輸入流和緩沖輸出流,怎麼獲得緩沖流對象呢?我們通過把方法1中的對象用緩沖流的構造方法包裝即可獲得。那麼什麼是緩沖呢?JVM記憶體中為它開辟了一塊區域,用來臨時存放資料,相當于是在方法1中加了一塊區域,讀到的位元組都會經過這個中間環節,先寫到緩沖區,當緩沖區讀滿或者給其相應強制清除緩沖的指令(flush方法)時,就會一次性讀取緩沖區的所有資料。它的優越之處顯而易見,CPU可以有更多的時間去處理别的事務了,一次性地讀取大大提升了讀取的速度,程式在性能上明顯優于方法1,我們在之後的測試中也可以看到。

3、自定義byte[] buf位元組數組建立緩沖區:和方法2的原理類似,但這種方法使得我們對資料的處理更加有可操作性,我們可以自己定義緩沖區的大小,因為這個空間是我們自己定義的。在流程上,我們先把資料寫入數組,擷取長度,再把位元組數組的資料寫到檔案中,這依然是一種批量操作。

測試三種方法copy檔案的速度(java程式)

1、代碼實作:我這裡分别寫了三個方法,測試程式傳檔案所花費的時間,第三種方法修改入口參數,可以自定義緩沖區位元組數組的長度。

public class Test {
	 public static void main(String[] args){
		 Test test = new Test();
		 test.withoutBuffer();//測試不加緩沖
		 test.addBuffer(); //測試加緩沖
		 test.BufferByte(1024);//自定義緩沖數組長度		 
	 }
	/**
	 * 不加緩沖的檔案傳輸測試
	 */
	public void withoutBuffer(){
		File file = new File("E:\\workspace\\mayifan\\src\\com\\myf\\bufferInputStream1211\\send\\雲計算必讀-Google_三大論文中文版.pdf");
		File file1 = new File("E:\\workspace\\mayifan\\src\\com\\myf\\bufferInputStream1211\\get\\雲計算必讀-Google_三大論文中文版.pdf");
		try{
		FileInputStream fis = new FileInputStream(file); //擷取檔案輸入流
		FileOutputStream fos = new FileOutputStream(file1); //擷取檔案輸出流
		int value=0;
	        long startTime = System.currentTimeMillis(); //執行前的時間
		while((value = fis.read())!=-1){   //讀取下一個位元組,傳回值是位元組對應的位元組對應的位元組值,讀到-1則表示沒有資料了
			fos.write(value);	//把這個位元組寫出去		
		}
		long endTime = System.currentTimeMillis(); //執行後的時間
		long time = endTime-startTime; //花費時間
		System.out.println("不加緩沖copy檔案用了:"+time+"ms");
		fos.close();  //關資源
		fis.close();		
		}catch(IOException e){
			e.printStackTrace();
		}			
	}
	/**
	 * 添加緩沖的檔案傳輸測試
	 */
	public void addBuffer(){
		File file = new File("E:\\workspace\\mayifan\\src\\com\\myf\\bufferInputStream1211\\send\\雲計算必讀-Google_三大論文中文版.pdf");
		File file1 = new File("E:\\workspace\\mayifan\\src\\com\\myf\\bufferInputStream1211\\get1\\雲計算必讀-Google_三大論文中文版.pdf");
		try{
		FileInputStream fis = new FileInputStream(file);
		BufferedInputStream bis = new BufferedInputStream(fis); //把檔案輸入流包裝為緩沖流
		FileOutputStream fos = new FileOutputStream(file1);
		BufferedOutputStream bos = new BufferedOutputStream(fos); //把檔案輸出流包裝為緩沖流
		int length=0;
	        long startTime = System.currentTimeMillis();
		while((length = bis.read())!=-1){
			bos.write(length);			
		}
		long endTime = System.currentTimeMillis();
		long time = endTime-startTime;	
		System.out.println("加緩沖後的檔案傳輸時間:"+time+"ms");
		bos.flush();
		bos.close();
		fos.close();
		bis.close();
		fis.close();					
		}catch(IOException e){
			e.printStackTrace();
		}				
	}
	/**
	 * 使用自定義的位元組數組作為緩沖區
	 */
	public void BufferByte(int len){
		File file = new File("E:\\workspace\\mayifan\\src\\com\\myf\\bufferInputStream1211\\send\\雲計算必讀-Google_三大論文中文版.pdf");
		File file1 = new File("E:\\workspace\\mayifan\\src\\com\\myf\\bufferInputStream1211\\get2\\雲計算必讀-Google_三大論文中文版.pdf");
		try{
		FileInputStream fis = new FileInputStream(file); //擷取檔案輸入流
		FileOutputStream fos = new FileOutputStream(file1); //擷取檔案輸出流
		int length=0; //記錄每次讀取到的位元組長度
		byte[] buf = new byte[len];  //根據輸入值自定義緩沖區長度
	        long startTime = System.currentTimeMillis(); //執行前的時間
		while((length = fis.read(buf))!=-1){   //讀取位元組到位元組數組中,最多一次讀1024個
			fos.write(buf,0,length);	//把這些資料寫到檔案
			if(length<len)  //最後的資料讀完後退出,防止阻塞
				break;
		}
		long endTime = System.currentTimeMillis(); //執行後的時間
		long time = endTime-startTime; //花費時間
		System.out.println("自定義緩沖位元組數組長度為"+len+"位元組時,copy檔案用了:"+time+"ms");
		fos.close();  //關資源
		fis.close();		
		}catch(IOException e){
			e.printStackTrace();
		}			
	}	
}
           

2、運作結果:

IO流不同方法copy檔案的效率分析
IO流不同方法copy檔案的效率分析
IO流不同方法copy檔案的效率分析
IO流不同方法copy檔案的效率分析

3、結果分析:觀察資料,我們可以發現,不加緩沖逐位元組讀取花費的時間是很長的,在程式運作的時候我們就可以明顯發現這一點。在加了java自帶的緩沖區後,檔案的傳輸速度明顯提升,隻需要幾十毫秒。copy速度最快的是第三種方法,我們自定義的緩沖區在1024位元組大小時,其速度略微慢于方法2,但當我們把緩沖區增加後,其速度就比方法2快了,且其記憶體區域越大,copy速度越快。是以,我們可以得出結論,最優的方案是自定義緩沖區,其次是采用java自帶緩沖區嗎,逐位元組讀取的方法我們應該盡量避免使用,效率低下。當程式反複讀寫的次數越少,其copy速度就會越快。查閱資料可以知道java自帶的緩沖區預設是8192位元組,在第二個測試案例中我們可以發現,自定義相同大小的區域,方法3是比方法2要快的,是以,效率最高的方法依然是自定義位元組數組作為緩沖區。