基於RandomAccessFile實現斷點檔案下載功能
阿新 • • 發佈:2019-02-19
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不屬於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); } }