RandomAccessFile和memory-mapped files


【0】README

0.1) 本文描述轉自 core Java volume 2, 旨在理解 java流與文件——RandomAccessFile類解析 的相關知識; 
0.1) 本文 轉自: http://blog.csdn.net/akon_vm/article/details/7429245 , for complete my diy code, please visit https://github.com/pacosonTang/core-java-volume/blob/master/coreJavaAdvanced/chapter1/BinaryIO.java


【1】RandomAccessFile類

1.1) RandomAccessFile是用來訪問那些保存數據記錄的文件的,你就可以用seek( )方法來訪問記錄,並進行讀寫了。這些記錄的大小不必相同;但是其大小和位置必須是可知的。但是該類僅限於操作文件。 
1.2)RandomAccessFile不屬於InputStream和OutputStream類系的。 (干貨——RandomAccessFile同InputStream和OutputStream類一樣,都繼承實現了DataInput和DataOutput接口,但RandomAccessFile類和后兩者之間沒有什么關系 )

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

1.3)基本上,RandomAccessFile的工作方式是,把DataInputStream和DataOutputStream結合起來,再加上它自己的一些方法。

  • 比如定位用的getFilePointer( ),在文件里移動用的seek( ),以及判斷文件大小的length( )、skipBytes()跳過多少字節數。此外,它的構造函數還要一個表示以只讀方式(“r”),還是以讀寫方式(“rw”)打開文件的參數 (和C的fopen( )一模一樣)。它不支持只寫文件。(干貨——RandomAccessFile不支持只寫文件,但支持r和rw訪問模式)

1.4)只有RandomAccessFile才有seek搜尋方法,而這個方法也只適用於文件。

  • BufferedInputStream有一個mark( )方法,你可以用它來設定標記(把結果保存在一個內部變量里),然后再調用reset( )返回這個位置,但是它的功能太弱了,而且也不怎么實用。 (干貨——RandomAccessFile類的seek 的作用等同於與 BufferedInputStream類的mark 方法和 reset方法結合)

1.5)RandomAccessFile的絕大多數功能,但不是全部,已經被JDK 1.4的nio的”內存映射文件(memory-mapped files)”給取代了。 
這里寫圖片描述

  • 你該考慮一下是不是用”內存映射文件”來代替RandomAccessFile了。(干貨——RandomAccessFile的絕大多數功能被nio的”內存映射文件(memory-mapped files)”給取代了,考慮使用內存映射文件來代替 RandomAccessFile)

【2】 內存映射文件

2.1)內存映射文件能讓你創建和修改那些因為太大而無法放入內存的文件。 (干貨——內存映射文件的作用)

  • 有了內存映射文件,你就可以認為文件已經全部讀進了內存,然后把它當成一個非常大的數組來訪問。這種解決辦法能大大簡化修改文件的代碼。 
    fileChannel.map(FileChannel.MapMode mode, long position, long size)將此通道的文件區域直接映射到內存中。
  • Attention)注意,你必須指明,它是從文件的哪個位置開始映射的,映射的范圍又有多大;也就是說,它還可以映射一個大文件的某個小片斷。

2.2)MappedByteBuffer是ByteBuffer的子類:因此它具備了ByteBuffer的所有方法,但新添了force()將緩沖區的內容強制刷新到存儲設備中去、load()將存儲設備中的數據加載到內存中、isLoaded()位置內存中的數據是否與存儲設置上同步。這里只簡單地演示了一下put()和get()方法,除此之外,你還可以使用asCharBuffer( )之類的方法得到相應基本類型數據的緩沖視圖后,可以方便的讀寫基本類型數據。 
這里寫圖片描述

2.3)盡管映射寫似乎要用到FileOutputStream,但是映射文件中的所有輸出 必須使用RandomAccessFile。

  • 但如果只需要讀時可以使用FileInputStream,寫映射文件時一定要使用隨機訪問文件,可能寫時要讀的原因吧。(干貨——只需要讀時可以使用FileInputStream,寫映射文件時一定要使用隨機訪問文件)

2.4)該程序創建了一個128Mb的文件,如果一次性讀到內存可能導致內存溢出,但這里訪問好像只是一瞬間的事,這是因為,真正調入內存的只是其中的一小部分,其余部分則被放在交換文件上。這樣你就可以很方便地修改超大型的文件了(最大可以到2 GB)。

  • Attention)注意,Java是調用操作系統的”文件映射機制”來提升性能的。

【3】看荔枝

3.1)RandomAccessFile類的應用: 
這里寫圖片描述

3.2)RandomAccessFile 插入寫示例: 
這里寫圖片描述

3.3)利用RandomAccessFile實現文件的多線程下載:

  • 即多線程下載一個文件時,將文件分成幾塊,每塊用不同的線程進行下載。下面是一個利用多線程在寫文件時的例子,其中預先分配文件所需要的空間,然后在所分配的空間中進行分塊,然后寫入:

這里寫圖片描述


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM