在網上看了一些關於java中的RandomAccessFile類的介紹,又經過查看Java API和自己編的測試程序,總算是對RandomAccessFile的使用有了一定的了解。自己做了以下比較詳細的總結吧。
1.RandomAccessFile類的簡單介紹
該類的實例支持對文件的隨機讀取和寫入。隨機存取文件的行為類似存儲在文件系統中的一個大型字節數組。存在指向該隱含數組的光標或索引,稱為文件指針。讀取操作從文件指針開始讀取字節,並隨着對字節的讀取而前移此文件指針。如果隨機存取文件以讀取/寫入模式創建,則寫入操作也可用;寫入操作從文件指針開始寫入字節,並隨着對字節的寫入而前移此文件指針。該文件指針可以通過 getFilePointer 方法讀取,並通過 seek 方法設置。
通常,如果此類中的所有讀取例程在讀取所需數量的字節之前已到達文件末尾,則拋出 EOFException。如果由於某些原因無法讀取任何字節,而不是在讀取所需數量的字節之前已到達文件末尾,則拋出 IOException。需要特別指出的是,如果流已被關閉,則可能拋出 IOException。
2.一個文件讀取錯誤例子引出的思考
import java.io.RandomAccessFile; public class RandomAccessFile_test { public static void main(String args[]) throws Exception{ RandomAccessFile access=new RandomAccessFile("c:\\a.txt","rw"); //文件a.txt中只有一個整數1234 System.out.println("文件長度為:"+access.length()); System.out.println("讀出的數據位:"+access.readInt()); access.close(); } }
執行輸出: 文件長度為:4
讀出的數據位:825373492
分析:這是因為RandomAccessFile類的實例都是根據要讀取的數據類型來讀取指定大小的數據塊到變量。int類型占4個字節,因此readInt()函數會從文件開頭讀取四個字節,每個字節都當做ASCII碼。讀到的四個ASCII碼字節是‘1’,‘2’,‘3’,‘4’,對應十六進制為31H,32H,33H,34H,即31323334H=825373492D。
3.隨機讀寫文件的存儲圖示
3.1數據存放
(1)用RandomAccessFile類寫入的數據一般都是按照ASCII字符的形式保存在文件中的,即以字節的形式,字節是計算機存儲設備編址的最小單元。
(2)Java中各數據類型所占的字節數,如圖表所示:

(3)如下圖就是依次寫入int,byte,double,int,byte,short,short數據時,在文件中的存放。文件指針會隨着數據的寫入按照寫入后移。

3.2數據讀取
(1)如用readInt()方法讀取一個int數據。文件指針會從當前位置向后讀取去四個字節的數據,將取到的數據在強制轉換為int類型返回即可,同時文件指針也自動的向后移動了相應的四個位置。
(2)如果先用readByte()方法讀取一個byte數據,讀取后文件指針移動了一個位置(還在int原本的四個字節中),這樣再用readInt()方法讀取一個int數據就會出現亂碼。
(3)也就是說用RandomAccessFile類來操作文件,應該知道數據事先是如何存放的,之后用相應的讀取就能順序的讀出,而不會出現亂碼。
4.特殊的數據讀取
4.1字符串讀readUTF()和字符串寫writeUTF(String str)
這2個方法都帶有“UTF”,是因為寫入數據時按照utf-8編碼寫入,讀取時也是utf-8。
每次寫入的字符串的長度是不一定的。因為Java API給出了讀取與寫入字符串是成對的,因此需要標記每次寫入的字符串的長度。每次寫入字符串時,會分配2個字節來保存,要寫入的字符串的大小,也就是一次寫入字符串的大小應該不能大於65536個字節。每次讀取的字符串時,先從文件指針的位置開始讀取2個字節,分析得到要讀取字符串的長度,之后在進行讀取。如下圖所示:

程序舉例:寫入2次字符串。
import java.io.RandomAccessFile; public class Char_Byte{ public static void main(String args[]) throws Exception{ RandomAccessFile access=new RandomAccessFile("C:\\a.txt","rw"); //“讀寫”方式建立類的實例 access.writeUTF("你好"); //以utf-8格式寫入數據 access.writeUTF("朋友"); //以utf-8格式寫入數據 access.close(); } }
查看生成文件:
,可以看到在漢字的前面有一些字符,其實就是2個字節的標記字符串長度的ASCII編碼。
4.2讀取一行readLine()
(1)Java API中只有讀取一行readLine()方法,然而沒有寫入一行writeLine()的方法。
(2)在Windows下的行結束符號是“\r\n”。執行readLine()方法,從當前的文件指針開始讀取,直到遇到“\r\n”或者文件結束為止。
(3)此方法不支持完整的 Unicode 字符集。所以用writeUTF(String str)寫入的中文需要相應的readUTF()讀取,以免出現亂碼。漢字的UTF-8編碼占3個字節,而GBK占用2個字節,漢字的Unicode編碼占2字節。
(4)在寫文件時,為了可以更換使用readLine(),需要自己寫入行結束符號是“\r\n”。
程序舉例:寫入2次字符串,以行結束符號隔開。
import java.io.RandomAccessFile; public class Char_Byte{ public static void main(String args[]) throws Exception{ RandomAccessFile access=new RandomAccessFile("C:\\a.txt","rw"); //“讀寫”方式建立類的實例 access.writeBytes("Hello world!!!"); //寫入數據 access.writeBytes("\r\n");//寫入行結束符號 access.writeUTF("he he"); //以utf-8格式寫入數據 access.close(); access=new RandomAccessFile("C:\\a.txt","rw"); String context=access.readLine(); //讀取數據 access.close(); System.out.println(context); } }
程序輸出:Hello world!!!
5.總結
(1)RandomAccessFile類可以進行文件的隨機讀寫,就好比對一個大型的數組的操作,對於大文件來說速度是比較慢的。
(2)RandomAccessFile類的實例是根據給定的數據類型大小寫入和讀取數據,因此用writeXXX()寫入的數據,最好用相應的readXXX()來讀取。
(3)RandomAccessFile類的實例寫入也是按照字節順序的寫入,生成文件的。要讀取這樣的文件就必須知道是如何生成的,否則很可能出現讀取出亂碼。
參考:
1.Java API文檔
