“嗨,阿米戈!”
“嗨,Bilaabo!生活怎麼樣?”
“太好了,昨天,我試著消滅了一些寄生蟲,但到目前為止我並沒有太大的成功。然後我又不得不在垃圾桶裡過夜了。”
“所以……一切還好嗎?”
“你可以那樣說。”
“好。那你今天有什麼事要給我?”
“今天我將向您介紹RandomAccessFile類。”
“問題是,FileInputStream 和 FileOutputStream 將文件表示為流:您只能順序讀取和寫入它們。”
“這並不總是非常方便。有時你需要在一個文件的中間寫幾行,或者從一個數兆字節的文件的末尾讀取幾頁文本。讀取效率不是很高這些任務的整個文件。”
“創建RandomAccessFile類是為了解決這個問題。您可以使用它在文件中的任何位置寫入、讀取以及同時讀取和寫入文件。”
“多麼有趣!”
“嗯,其實挺方便的。”
“但是你如何從任意位置讀取數據呢?”
“這一切都很簡單。想像一下,你有一個文本編輯器,比如記事本,打開。它有一個光標。當你輸入一些東西時,文本會添加到光標所在的位置。讀取文件也是一樣的。閱讀從‘光標’在哪,讀/寫時,光標自動移動。”
“這裡,給你舉個例子比較好:”
// r - read, the file is opened only for reading.
RandomAccessFile raf = new RandomAccessFile("input.txt", "r");
// Move the «cursor» to the 100th character.
raf.seek(100);
// Read the line starting from the current cursor position until the end of the line.
String text = raf.readLine();
// Close the file.
raf.close();
“在這個例子中,我想提請你注意兩件事:”
"首先,創建RandomAccessFile對象。第二個參數是字母 r。這意味著打開文件進行讀取(r - read)。如果要打開文件進行讀取和寫入,則必須通過 « rw » 給構造函數,而不僅僅是 « r »。”
”其次,看seek方法。你可以使用這個方法在文件中跳轉,改變當前讀/寫操作的光標位置。當一個文件第一次打開時,光標被設置為第0個字節。或者,更準確地說,在第零個字節之前。”
“我沒理解錯嗎?我們打開文件,光標在最開始——位置 0。然後我們調用seek並將光標移動到第 100 個字節。當我們調用readLine時,它從第 100 個字節開始讀取。 正確的?”
“是的。但我想提請你注意,seek 方法允許你在文件中任意跳轉。例如:”
// r - read, the file is opened only for reading.
RandomAccessFile raf = new RandomAccessFile("input.txt", "r");
// The "cursor" is at the 0th character.
String text1 = raf.readLine();
// Move the "cursor" to the 100th character.
raf.seek(100);
String text2 = raf.readLine();
// Move the "cursor" to the 0th character.
raf.seek(0);
String text3 = raf.readLine();
// Close the file
raf.close();
“在這個例子中,我們首先從第 0 個字節開始讀取一行。然後我們跳到第 100 個字節並在那裡讀取一行。然後我們再次跳到第 0 個字節並讀取一行。這意味著 text1 和 text3 是相同的字符串。”
“啊。這讓事情更清楚了。”
“太好了。那麼這是另一個例子:”
// rw - read/write, the file is opened for reading and writing.
RandomAccessFile raf = new RandomAccessFile("seek.txt", "rw");
// Write to the file, starting from the 0th byte.
raf.writeBytes("It is a string");
// Move the "cursor" to the 8th character.
raf.seek(8);
// Write "surprise!" to the file.
raf.writeBytes("surprise!");
// Close the file.
raf.close();
“在這裡,我們通過將 « rw »(讀/寫)傳遞給構造函數來打開文件進行讀寫。”
“然後我們將 « It is a string » 寫入文件。
“然後我們將光標移動到第 8 個字節(恰好是單詞‘string’的開頭)”
“然後我們寫 «驚喜!»”
“結果,該文件包含 «這是一個驚喜!»”
“所以,字節並沒有插入到文件的中間,而是替換了原來的字節?”
“是的。”
“如果我們將光標移動到文件的最後呢?”
“然後字節會寫到最後,文件會變大。所以這幾乎就像在文本編輯器中寫入文本一樣。”
“嗯。我想我明白了一切。你能提供RandomAccessFile類的方法的完整列表嗎?”
“喏,給你:”
方法 | 描述 |
---|---|
int read() |
讀取一個字節並返回它 |
int read(byte b[], int off, int len) |
讀取字節數組 |
int read(byte b[]) |
讀取字節數組 |
void readFully(byte b[]) |
讀取字節數組,如果沒有足夠的字節來填充數組,則等待添加新字節 |
int skipBytes(int n) |
跳過 n 個字節。換句話說,這會將光標向前移動 n 個字節。 |
void write(int b) |
將一個字節寫入光標位置 |
void write(byte b[]) |
將字節數組寫入光標位置 |
void write(byte b[], int off, int len) |
將字節數組寫入光標位置 |
long getFilePointer() |
返迴光標指向的字節數。它的範圍可以從 0 到文件長度 |
void seek(long pos) |
將用於讀/寫的 «cursor» 移動到指定位置 |
long length() |
返回文件長度 |
void setLength(long newLength) |
設置新的文件長度。如果文件較大,則會被截斷;如果它更小,那麼它會擴展文件並用零填充新空間 |
void close() |
關閉文件 |
boolean readBoolean() |
從光標在文件中的當前位置讀取一個布爾值 |
byte readByte() |
從光標在文件中的當前位置讀取一個字節 |
char readChar() |
從光標在文件中的當前位置讀取一個字符 |
int readInt() |
從光標在文件中的當前位置讀取一個 int |
long readLong() |
從光標在文件中的當前位置讀取一個 long |
float readFloat() |
從光標在文件中的當前位置讀取一個浮點數 |
double readDouble() |
從光標在文件中的當前位置讀取一個 double |
String readLine() |
從文件中讀取一行並返回 |
void writeBoolean(boolean v) |
將布爾值寫入文件(從光標位置開始) |
void writeByte(int v) t |
向文件寫入一個字節(從光標位置開始) |
void writeChar(int v) |
將一個字符寫入文件(從光標位置開始) |
void writeInt(int v) |
將一個 int 寫入文件(從光標位置開始) |
void writeLong(long v) |
向文件寫入一個 long(從光標位置開始) |
void writeFloat(float v) |
將浮點數寫入文件(從光標位置開始) |
void writeDouble(double v) |
向文件寫入一個雙精度值(從光標位置開始) |
void writeBytes(String s) |
將字符串寫入文件(從光標位置開始) |
void writeChars(String s) |
將字符串寫入文件(從光標位置開始) |
“嗯。所以,這裡沒有什麼新東西。除了 seek()/getFilePointer() 和 length()/setLength() 方法對。”
“是的,阿米戈。一切都差不多。但這不是很方便嗎?”
“這很方便。謝謝你,Bilaabo,給了我有趣的課程和你給我的例子。”
“很高興能幫上忙,阿米戈,我的朋友!”
GO TO FULL VERSION