隨機訪問文件RandomAccessFile 與 內存映射文件MappedByteBuffer

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了。
Java代碼
import java.io.IOException;
import java.io.RandomAccessFile;

public class TestRandomAccessFile {
public static void main(String[] args) throws IOException {
RandomAccessFile rf = new RandomAccessFile("rtest.dat", "rw");
for (int i = 0; i < 10; i++) {
//寫入基本類型double數據
rf.writeDouble(i * 1.414);
}
rf.close();
rf = new RandomAccessFile("rtest.dat", "rw");
//直接將文件指針移到第5個double數據後面
rf.seek(5 * ; //覆蓋第6個double數據 rf.writeDouble(47.0001); rf.close(); rf = new RandomAccessFile("rtest.dat", "r"); for (int i = 0; i < 10; i++) { System.out.println("Value " + i + ": " + rf.readDouble()); } rf.close(); } } 內存映射文件 內存映射文件能讓你建立和修改那些由於太大而沒法放入內存的文件。有了內存映射文件,你就能夠認爲文件已經所有讀進了內存,而後把它當成一個很是大的數組來訪問。這種解決辦法能大大簡化修改文件的代碼。 fileChannel.map(FileChannel.MapMode mode, long position, long size)將此通道的文件區域直接映射到內存中。注意,你必須指明,它是從文件的哪一個位置開始映射的,映射的範圍又有多大;也就是說,它還能夠映射一個大文件的某個小片段。 MappedByteBuffer是ByteBuffer的子類,所以它具有了ByteBuffer的全部方法,但新添了force()將緩衝區的內容強制刷新到存儲設備中去、load()將存儲設備中的數據加載到內存中、isLoaded()位置內存中的數據是否與存儲設置上同步。這裏只簡單地演示了一下put()和get()方法,除此以外,你還可使用asCharBuffer( )之類的方法獲得相應基本類型數據的緩衝視圖後,能夠方便的讀寫基本類型數據。 Java代碼 import java.io.RandomAccessFile; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; public class LargeMappedFiles { static int length = 0x8000000; // 128 Mb public static void main(String[] args) throws Exception { // 爲了以可讀可寫的方式打開文件,這裏使用RandomAccessFile來建立文件。 FileChannel fc = new RandomAccessFile("test.dat", "rw").getChannel(); //注意,文件通道的可讀可寫要創建在文件流自己可讀寫的基礎之上 MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_WRITE, 0, length); //寫128M的內容 for (int i = 0; i < length; i++) { out.put((byte) 'x'); } System.out.println("Finished writing"); //讀取文件中間6個字節內容 for (int i = length / 2; i < length / 2 + 6; i++) { System.out.print((char) out.get(i)); } fc.close(); } } 儘管映射寫彷佛要用到FileOutputStream,可是映射文件中的全部輸出 必須使用RandomAccessFile,但若是隻須要讀時可使用FileInputStream,寫映射文件時必定要使用隨機訪問文件,可能寫時要讀的緣由吧。 該程序建立了一個128Mb的文件,若是一次性讀到內存可能致使內存溢出,但這裏訪問好像只是一瞬間的事,這是由於,真正調入內存的只是其中的一小部分,其他部分則被放在交換文件上。這樣你就能夠很方便地修改超大型的文件了(最大能夠到2 GB)。注意,Java是調用操做系統的"文件映射機制"來提高性能的。 RandomAccessFile類的應用 收藏 /* * 程序功能:演示了RandomAccessFile類的操做,同時實現了一個文件複製操做。 */ package com.lwj.demo; import java.io.*; public class RandomAccessFileDemo { public static void main(String[] args) throws Exception { RandomAccessFile file = new RandomAccessFile("file", "rw"); // 如下向file文件中寫數據 file.writeInt(20);// 佔4個字節 file.writeDouble(8.236598);// 佔8個字節 file.writeUTF("這是一個UTF字符串");// 這個長度寫在當前文件指針的前兩個字節處,可用readShort()讀取 file.writeBoolean(true);// 佔1個字節 file.writeShort(395);// 佔2個字節 file.writeLong(2325451l);// 佔8個字節 file.writeUTF("又是一個UTF字符串"); file.writeFloat(35.5f);// 佔4個字節 file.writeChar('a');// 佔2個字節 file.seek(0);// 把文件指針位置設置到文件起始處 // 如下從file文件中讀數據,要注意文件指針的位置 System.out.println("——————從file文件指定位置讀數據——————"); System.out.println(file.readInt()); System.out.println(file.readDouble()); System.out.println(file.readUTF()); file.skipBytes(3);// 將文件指針跳過3個字節,本例中即跳過了一個boolean值和short值。 System.out.println(file.readLong()); file.skipBytes(file.readShort()); // 跳過文件中「又是一個UTF字符串」所佔字節,注意readShort()方法會移動文件指針,因此不用加2。 System.out.println(file.readFloat()); //如下演示文件複製操做 System.out.println("——————文件複製(從file到fileCopy)——————"); file.seek(0); RandomAccessFile fileCopy=new RandomAccessFile("fileCopy","rw"); int len=(int)file.length();//取得文件長度(字節數) byte[] b=new byte[len]; file.readFully(b); fileCopy.write(b); System.out.println("複製完成!"); } } 運行結果(同時生成相應的文件): ——————從file文件指定位置讀數據—————— 20 8.236598 這是一個UTF字符串 2325451 35.5 ——————文件複製(從file到fileCopy)——————
相關文章
相關標籤/搜索