1. 程式人生 > >IO流不同方法copy檔案的效率分析

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