通過前面的學習我們知道,如果準備讀文件,需要建立指向該文件的輸入流;如果準備寫文件,需要建立指向該文件的輸出流。那么,能否建立一個流,通過該流既能讀文件也能寫文件呢?這正是本節(jié)要介紹的隨機流。
RandomAccessFile類創(chuàng)建的流稱做隨機流,與前面的輸入、輸出流不同的是,RandomAccessFile類既不是InputStream類的子類,也不是OutputStream類的子類。但是RandomAccessFile類創(chuàng)建的流的指向既可以作為流的源,也可以作為流的目的地,換句話說,當準備對一個文件進行讀寫操作時,創(chuàng)建一個指向該文件的隨機流即可,這樣既可以從這個流中讀取文件中的數(shù)據(jù),也可以通過這個流寫入數(shù)據(jù)到文件。
以下是RandomAccessFile類的兩個構造方法:
1)RandomAccessFile(String name,String mode)
參數(shù)name用來確定一個文件名,給出創(chuàng)建的流的源,也是流目的地。參數(shù)mode取r(只讀)或rw(可讀寫),決定創(chuàng)建的流對文件的訪問權利。
2)RandomAccessFile(File file,String mode)
參數(shù)file是一個File對象,給出創(chuàng)建的流的源,也是流目的地。參數(shù)mode取r(只讀)或rw(可讀寫),決定創(chuàng)建的流對文件的訪問權利。
注意:RandomAccessFile流指向文件時,不刷新文件。
RandomAccessFile類中有一個方法seek(long a)用來定位RandomAccessFile流的讀寫位置,其中參數(shù)a確定讀寫位置距離文件開頭的字節(jié)個數(shù)。另外流還可以調用getFilePointer()方法獲取流的當前讀寫位置。RandomAccessFile流對文件的讀寫比順序讀寫更為靈活。
例如,把幾個int型整數(shù)寫入到一個名字為tom.dat文件中,然后按相反順序讀出這些數(shù)據(jù):
import java.io.*; public class Main { public static void main(String args[]) { RandomAccessFile inAndOut = null; int data[] = {1,2,3,4,5,6,7,8,9,10}; try { inAndOut = new RandomAccessFile("tom.dat","rw"); for(int i=0;i<data.length;i++) { inAndOut.writeInt(data[i]); } for(long i = data.length-1;i>=0;i--) { inAndOut.seek(i*4); System.out.printf("\t%d",inAndOut.readInt()); /* 一個int型數(shù)據(jù)占4個字節(jié),inAndOut從文件的第36個字節(jié)讀取最后面的一個整數(shù),每隔4個字節(jié)往前讀取一個整數(shù) */ } inAndOut.close(); } catch(IOException e) {} } }
RandomAccessFile流的常用方法如下:
方法 | 說明 |
close() | 關閉文件 |
getFilePointer() | 獲取當前讀寫的位置 |
length() | 獲取文件的長度 |
read() | 從文件中讀取一個字節(jié)的數(shù)據(jù) |
readBoolean() | 從文件中讀取一個布爾值,0代表false;其他值代表true |
readByte() | 從文件中讀取一個字節(jié) |
readChar() | 從文件中讀取一個字符(2個字節(jié)) |
readDouble() | 從文件中讀取一個雙精度浮點值(8 個字節(jié)) |
readFloat() | 從文件中讀取一個單精度浮點值(4個字節(jié)) |
readFully(byte b[]) | 讀b.length字節(jié)放入數(shù)組b,完全填滿該數(shù)組 |
readInt() | 從文件中讀取一個int值(4個字節(jié)) |
readLine() | 從文件中讀取一個文本行 |
readLong() | 從文件中讀取一個長型值(8個字節(jié)) |
readShort() | 從文件中讀取一個短型值(2個字節(jié)) |
readUnsignedByte() | 從文件中讀取一個無符號字節(jié)(1個字節(jié)) |
readUnsignedShort() | 從文件中讀取一個無符號短型值(2個字節(jié)) |
readUTF() | 從文件中讀取一個UTF字符串 |
seek(long position) | 定位讀寫位置 |
setLength(long newlength) | 設置文件的長度 |
skipBytes(int n) | 在文件中跳過給定數(shù)量的字節(jié) |
write(byte b[]) | 寫b.length個字節(jié)到文件 |
writeBoolean(boolean v) | 把一個布爾值作為單字節(jié)值寫入文件 |
writeByte(int v) | 向文件寫入一個字節(jié) |
writeBytes(String s) | 向文件寫入一個字符串 |
writeChar(char c) | 向文件寫入一個字符 |
writeChars(String s) | 向文件寫入一個作為字符數(shù)據(jù)的字符串 |
writeDouble(double v) | 向文件寫入一個雙精度浮點值 |
writeFloat(float v) | 向文件寫入一個單精度浮點值 |
writeInt(int v) | 向文件寫入一個int值 |
writeLong(long v) | 向文件寫入一個長型int值 |
writeShort(int v) | 向文件寫入一個短型int值 |
writeUTF(String s) | 寫入一個UTF字符串 |
注意:RandomAccessFile流的readLine()方法在讀取含有非ASCⅡ字符的文件時,比如含有漢字的文件,會出現(xiàn)“亂碼”現(xiàn)象。因此,需要把readLine()讀取的字符串用“iso-8859-1”編碼重新編碼存放到byte數(shù)組中,然后再用當前機器的默認編碼將該數(shù)組轉化為字符串,操作如下:
1.讀取
String str = in.readLine();
2.用“iso-8859-1”重新編碼
byte b[] = str.getBytes("iso-8859-1");
3.使用當前機器的默認編碼將字節(jié)數(shù)組轉化為字符串
String content = new String(b);
如果機器的默認編碼是“GB2312”,那么
String content = new String(b);
等同于
String content = new String(b,"GB2312");
例如:
import java.io.*; public class Main { public static void main(String args[]) { RandomAccessFile in = null; try { in = new RandomAccessFile("Main.java","rw"); long length = in.length(); //獲取文件的長度 long position = 0; in.seek(position); //將讀取位置定位到文件的起始 while(position<length) { String str = in.readLine(); byte b[] = str.getBytes("iso-8859-1"); str = new String(b); position = in.getFilePointer(); System.out.println(str); } } catch(IOException e) {} } }
C語言網提供由在職研發(fā)工程師或ACM藍橋杯競賽優(yōu)秀選手錄制的視頻教程,并配有習題和答疑,點擊了解:
一點編程也不會寫的:零基礎C語言學練課程
解決困擾你多年的C語言疑難雜癥特性的C語言進階課程
從零到寫出一個爬蟲的Python編程課程
只會語法寫不出代碼?手把手帶你寫100個編程真題的編程百練課程
信息學奧賽或C++選手的 必學C++課程
藍橋杯ACM、信息學奧賽的必學課程:算法競賽課入門課程
手把手講解近五年真題的藍橋杯輔導課程