1. 程式人生 > 實用技巧 >隨機存取檔案流(雙性流)

隨機存取檔案流(雙性流)

隨機存取檔案流

RandomAccessFile類(雙性流)

  • RandomAccessFile宣告在java.io包下,單直接繼承於java.lang.Object類。並且它實現了DataInput,DataOutput這兩個介面,也就意味著這個類既可以讀也可以寫。

  • RandomAccessFile類支援“隨機訪問”的方式,程式可以直接跳到檔案的任意地方來讀,寫檔案

    • 支援只訪問檔案的部分內容
    • 可以向已存在的檔案後追加內容
  • RandomAccessFile物件包含一個記錄指標,用以標示當前讀寫的位置。

    RandomAccessFile類物件可以自由移動記錄指標:

    • long getFilePointer()
      ; 獲取檔案記錄指標的當前位置
    • void seek(long pos); 將檔案記錄指標定位到pos位置
  • 構造器

    public RandomAccessFile(File file,String mode);
    public RandomAccessFile(String name,String mode);
    
  • 建立 RandomAccessFile 類例項需要指定一個mode引數,該引數指定RandomAccessFile的訪問模式:

    1. r:以只讀方式開啟
    2. rw:開啟以便讀取和寫入
    3. rwd:開啟以便讀取和寫入:同步檔案內容的更新
    4. rws:開啟以便讀取和寫入:同步檔案內容和元資料的更新
  • 如果模式為只讀r。則不會建立檔案,而是會去讀一個已經存在的檔案,如果讀取的檔案不存在則會出現異常。如果模式為rw讀寫。如果檔案不存在則回去建立檔案,如果存在則不會建立(如果寫入檔案時則會對原始檔內容進行覆蓋預設從頭覆蓋)。

    JDK1.6上面每次write資料時,”rw“模式,資料不會立即寫入到硬碟中;而”rwd“,資料會被立即寫入硬碟。如果寫資料過程發生異常,”rwd“模式中已被write的資料被儲存到硬碟,而”rw“這全部丟失。

  • 我們可以用RandomAccessFile 這個類,來實現一個多執行緒斷點下載的功能,用過下載工具的朋友都知道,下載前都會建立兩個臨時檔案,一個是於被下載檔案相同的空檔案,另一個是記錄檔案指標的位置檔案,每次暫停的時候,都會儲存上一次的指標,然後斷點下載或上傳的功能。

程式碼例項

  • r--rw

    import java.io.File;
    import java.io.IOException;
    import java.io.RandomAccessFile;
    
    public class RandomAccessFileTest {
        public static void main(String[] args) {
    //        demo1();
    //        demo2();
    //        demo3();
    //        demo4();
        }
    
        //r--rw
        public static void demo1() {
            //jdk8 新特性
            try (RandomAccessFile raf1 = new RandomAccessFile(new File("day30_IO/12.jpeg"), "r");
                 RandomAccessFile raf2 = new RandomAccessFile(new File("day30_IO/12.jpeg"), "rw")) {
                byte[] buffer = new byte[1024];
                int len;
                while ((len = raf1.read(buffer)) != -1) {
                    raf2.write(buffer, 0, len);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        //rw 如果檔案不存在則會建立檔案寫入資料/如果檔案存在則會對原有的檔案的覆蓋從開頭為位置
        public static void demo2() {
            try (
                    RandomAccessFile raf1 = new RandomAccessFile("day30_IO/a.txt", "rw");
            ) {
                raf1.write("xyz".getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static void demo3() {
            try (
                    RandomAccessFile raf1 = new RandomAccessFile("day30_IO/a.txt", "rw");
            ) {
                raf1.seek(3);//將指標調到角標為3的位置
                raf1.write("xyz".getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        //實現資料插入效果
        public static void demo4() {
            try (
                    RandomAccessFile raf1 = new RandomAccessFile("day30_IO/a.txt", "rw");
            ) {
                raf1.seek(3);//將指標調到角標為3的位置
                //儲存指標3後面的所有資料到StringBuilder中
                StringBuilder sb = new StringBuilder((int) new File("day30_IO/a.txt").length());
                byte[] buffer = new byte[20];
                int len;
                while ((len = raf1.read(buffer)) != -1) {
                    sb.append(new String(buffer));
                }
                //調回指標,寫入xyz
                raf1.seek(3);
                raf1.write("xyz".getBytes());
                //將StringBuilder中資料寫入到檔案中
                raf1.write(sb.toString().getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    //擴充套件:將StringBuilder替換成ByteArrayOutputStream