1. 程式人生 > >基於RandomAccessFile實現斷點檔案下載功能

基於RandomAccessFile實現斷點檔案下載功能

RandomAccessFile是用來訪問那些儲存資料記錄的檔案的,你就可以用seek( )方法來訪問記錄,並進行讀寫了。這些記錄的大小不必相同;但是其大小和位置必須是可知的。但是該類僅限於操作檔案。

RandomAccessFile不屬於InputStream和OutputStream類系的。實際上,除了實現DataInput和DataOutput介面之外(DataInputStream和DataOutputStream也實現了這兩個介面),它和這兩個類系毫不相干,甚至不使用InputStream和OutputStream類中已經存在的任何功能;它是一個完全獨立的類,所有方法(絕大多數都只屬於它自己)都是從零開始寫的。這可能是因為RandomAccessFile能在檔案裡面前後移動,所以它的行為與其它的I/O類有些根本性的不同。總而言之,它是一個直接繼承Object的,獨立的類。


基本上,RandomAccessFile的工作方式是,把DataInputStream和DataOutputStream結合起來,再加上它自己的一些方法,比如定位用的getFilePointer( ),在檔案裡移動用的seek( ),以及判斷檔案大小的length( )、skipBytes()跳過多少位元組數。此外,它的建構函式還要一個表示以只讀方式("r"),還是以讀寫方式("rw")開啟檔案的引數 (和C的fopen( )一模一樣)。它不支援只寫檔案。

只有RandomAccessFile才有seek搜尋方法,而這個方法也只適用於檔案。BufferedInputStream有一個mark( )方法,你可以用它來設定標記(把結果儲存在一個內部變數裡),然後再呼叫reset( )返回這個位置,但是它的功能太弱了,而且也不怎麼實用。


RandomAccessFile的絕大多數功能,但不是全部,已經被JDK 1.4的nio的"記憶體對映檔案(memory-mapped files)"給取代了,你該考慮一下是不是用"記憶體對映檔案"來代替RandomAccessFile了。

以下是例項原始碼:

public class ContinueCopy {
	
	public void copy(File file,File dir){
		RandomAccessFile raf_read  = null;
		RandomAccessFile raf_write = null;
		long position = 0;
		int count = 0;
		try {
			position = readPosition(dir);
			
			//以只讀模式開啟一個檔案訪問流
			raf_read = new RandomAccessFile(file,"r");
			File target = new File(dir,file.getName());
			//以讀寫模式開啟一個檔案訪問流
			raf_write = new RandomAccessFile(target,"rw");
			
			raf_read.seek(position);
			raf_write.seek(position);
			byte[] b = new byte[1024];
			int len = 0;
			System.out.println("準備開始拷貝");
			while((len = raf_read.read(b)) != -1){
				count++;
				position += len;
				if(count == 8800){
					System.out.println("出現異常,拷貝終止-->"+position);
					throw new Exception();
				}
				
				//獲取檔案指標的位置
				raf_write.write(b,0,len);
				
			}
			new File(dir,"len.txt").delete();
			System.out.println("拷貝完成");
		}  catch (Exception e) {
			writePosition(position,dir);
			e.printStackTrace();
			
		}finally{
			try {
				if(raf_write != null)raf_write.close();
				if(raf_read != null)raf_read.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}
	//實時地記錄檔案拷貝(下載)到目標位置
	public void writePosition(long position,File dir){
		RandomAccessFile raf = null;
		try {
			 raf = new RandomAccessFile(new File(dir,"len.txt"),"rw");
			 raf.writeLong(position);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
		
				try {	if(raf != null)
					raf.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
		
	}
	
	public long readPosition(File dir){
		RandomAccessFile raf = null;
		try {
			raf = new RandomAccessFile((new File(dir,"len.txt")),"r");
		//	raf.seek(0);
			return raf.readLong();
		} catch (FileNotFoundException e) {
//			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			
				try {
					if(raf != null)
					raf.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
		return 0L;
	}
	public static void main(String[] args) {
		File source = new File("d:/test1/1.mp4");
		File dir = new File("d:/1/");
		new ContinueCopy().copy(source, dir);
	}
}