天天看點

利用IO流對檔案進行分割和無損還原合并

1、實作原理分布寫在注釋裡,基本思路是将源檔案分割為若幹份,之後再将分割的檔案進行合并還原。

2、實作代碼如下:

package com.tiger.copy.split.combine;

import java.io.*;
/**
 * 檔案的分割與合并
 * @author tiger
 * @Date 2017年7月21日
 */
public class FileSplitAndCombine {
	/*
	 * 測試
	 */
	public static void main( String[] args ) 
			throws IOException {
		String cPath = "E:\\tigerFolder\\J2SE6.0 API(冷冬大雪).chm";
		String sPath = "E:\\tigerFolder\\split";
		fileSplit(cPath,sPath,9,1024,"chm");
		/*================================================================*/
//		String srcPath = "E:\\tigerFolder\\split";
//		String destPath = "E:\\tigerFolder\\combine.chm";
//		fileCombine(srcPath,destPath,9,1024,".chm");
		
	}
	/**
	 * 檔案的切割
	 * @param srcPath 切割源檔案路徑
	 * @param destPath 合并檔案路徑
	 * @param size 切割塊數
	 * @param speed 切割速度
	 * @param suffix 切割檔案字尾
	 * @throws IOException 異常處理
	 */
	public static void fileSplit(String srcPath,String destPath,
	int size,int speed,String suffix) throws IOException{
		long start = System.currentTimeMillis();
		InputStream is = new FileInputStream( srcPath );
		//擷取檔案可讀取的位元組數,依據這個對檔案進行分割
		int total = is.available();
		//檔案分塊切割數目 size,餘數放到最後一個檔案中。
		int[] blocks = new int[size];
		for (int i = 0; i < size; i++) {
			if (i == size - 1) {
				blocks[i] = total/size + total%size;
			}else {
				blocks[i] = total/size;
			}
		}
		//定義建立 size 個輸出流的數組.
		OutputStream[] outs = new OutputStream[ size ];
		for (int i = 0; i < outs.length; i++) {
			outs[i] = new FileOutputStream( destPath + i + suffix);
		}

		int index = 0; 
		//表示要讀取到哪一塊,一塊一塊地讀取
		int remain = blocks[ index ];
		//記錄當次需要讀取多少個位元組
		int needRead;   
		int len = 0;
		byte[] buff = new byte[speed];
		while( index < size ){
			//處理數組越界問題
			if( remain > speed ){
				needRead = speed;
			}else{
				needRead = remain;
			}
			//讀取資料
			len = is.read( buff, 0, needRead );
			if( len != -1 ){   
				//寫出資料、讀多少, 寫多少
				outs[index].write( buff, 0, len );
				//強制重新整理資料
				outs[index].flush();
				//讀多少減多少
				remain = remain - len; 
				//索引指向下一個檔案塊
				if( remain == 0 ){
					index ++; 
					if( index < size ){
						remain = blocks[index];
					}
				}
			}
		}
		is.close();
		long end = System.currentTimeMillis();
		System.out.println("執行檔案切割耗時: "+(end - start)/1000 + " s");
		System.out.println( "程式結束 ..." );
	}
	/**
	 * 檔案的合并
	 * @param srcPath 分散檔案源檔案路徑
	 * @param destPath 合并成功後檔案的存放路徑
	 * @param size 源檔案數目
	 * @param speed 合并速度
	 * @param suffix 合并檔案字尾
	 * @throws IOException 異常處理
	 */
	public static void fileCombine(String srcPath,String destPath,
	int size,int speed,String suffix) throws IOException{
		long start = System.currentTimeMillis();
		//目标輸出流
		OutputStream os = new FileOutputStream(destPath,true);//輸出的追加的後邊
		//定義建立 4 個輸入流的數組.
		InputStream[] is = new InputStream[size];
		for (int i = 0; i < size; i++) {
			is[i] = new FileInputStream(srcPath + i + suffix);
		}
		//擷取每個檔案大小
		int[] blocks = new int[size];
		for (int i = 0; i < size; i++) {
			blocks[i] = is[i].available();
		}
		int needRead;//一次
		int index = 0;//檔案号索引
		int remain = blocks[index];//記錄讀取到哪個檔案
		byte[] buff = new byte[speed];//緩沖,每次讀取的大小
		int len = 0;//接收資料
		while (index < size) {
			if( remain > speed ){
				needRead = speed;
			}else{
				needRead = remain;  //剩餘數 ...
			}
			//讀一次,寫一次
			len = is[index].read(buff, 0, needRead);//如果位元組夠,則将byte數組中的資料讀完,否則讀剩下的。
			if (len != -1) {//邊讀取邊輸出到本地檔案中,讀多少,輸出多少
				os.write(buff, 0, len);//off  需要一個标簽來記錄,将檔案輸入到指定檔案中。
				//讀多少,減多少,直到檔案大小被減為0 ,則表明檔案被讀取完畢,接着判斷讀取下一個檔案
				remain = remain - len;
			}
			if( remain == 0 ){//表明檔案被讀取完畢,接着判斷讀取下一個檔案
				//記錄檔案号
				index ++; 
				if( index < size ){
					remain = blocks[index];
				}
			}
		}
		os.close();
		long end = System.currentTimeMillis();
		System.out.println("執行檔案合并耗時: "+(end - start)/1000 + " s");
		System.out.println( "程式結束 ..." );
	}
}