本篇文章主要介紹RandomAccessFile,該類是IO流體系中功能最豐富的文件內(nèi)容訪問(wèn)類例证,既可以讀取文件內(nèi)容路呜,也可以向文件輸出數(shù)據(jù)。
一、RandomAccessFile簡(jiǎn)介
RandomAccessFile既可以讀取文件內(nèi)容胀葱,也可以向文件輸出數(shù)據(jù)漠秋。同時(shí),RandomAccessFile支持“隨機(jī)訪問(wèn)”的方式抵屿,程序快可以直接跳轉(zhuǎn)到文件的任意地方來(lái)讀寫數(shù)據(jù)庆锦。
由于RandomAccessFile可以自由訪問(wèn)文件的任意位置,所以如果需要訪問(wèn)文件的部分內(nèi)容轧葛,而不是把文件從頭讀到尾搂抒,使用RandomAccessFile將是更好的選擇。
與OutputStream尿扯、Writer等輸出流不同的是求晶,RandomAccessFile允許自由定義文件記錄指針,RandomAccessFile可以不從開始的地方開始輸出衷笋,因此RandomAccessFile可以向已存在的文件后追加內(nèi)容芳杏。如果程序需要向已存在的文件后追加內(nèi)容,則應(yīng)該使用RandomAccessFile辟宗。
RandomAccessFile的方法雖然多爵赵,但它有一個(gè)最大的局限,就是只能讀寫文件泊脐,不能讀寫其他IO節(jié)點(diǎn)空幻。
RandomAccessFile的一個(gè)重要使用場(chǎng)景就是網(wǎng)絡(luò)請(qǐng)求中的多線程下載及斷點(diǎn)續(xù)傳。
二晨抡、RandomAccessFile中的方法
1.RandomAccessFile的構(gòu)造函數(shù)
RandomAccessFile類有兩個(gè)構(gòu)造函數(shù)氛悬,其實(shí)這兩個(gè)構(gòu)造函數(shù)基本相同,只不過(guò)是指定文件的形式不同——一個(gè)需要使用String參數(shù)來(lái)指定文件名耘柱,一個(gè)使用File參數(shù)來(lái)指定文件本身如捅。除此之外,創(chuàng)建RandomAccessFile對(duì)象時(shí)還需要指定一個(gè)mode參數(shù)调煎,該參數(shù)指定RandomAccessFile的訪問(wèn)模式镜遣,一共有4種模式。
**"r" : ** 以只讀方式打開士袄。調(diào)用結(jié)果對(duì)象的任何 write 方法都將導(dǎo)致拋出 IOException悲关。
"rw": 打開以便讀取和寫入。
"rws": 打開以便讀取和寫入娄柳。相對(duì)于 "rw"寓辱,"rws" 還要求對(duì)“文件的內(nèi)容”或“元數(shù)據(jù)”的每個(gè)更新都同步寫入到基礎(chǔ)存儲(chǔ)設(shè)備。
"rwd" : 打開以便讀取和寫入赤拒,相對(duì)于 "rw"秫筏,"rwd" 還要求對(duì)“文件的內(nèi)容”的每個(gè)更新都同步寫入到基礎(chǔ)存儲(chǔ)設(shè)備诱鞠。
2.RandomAccessFile的重要方法
RandomAccessFile既可以讀文件,也可以寫文件这敬,所以類似于InputStream的read()方法航夺,以及類似于OutputStream的write()方法,RandomAccessFile都具備崔涂。除此之外阳掐,RandomAccessFile具備兩個(gè)特有的方法,來(lái)支持其隨機(jī)訪問(wèn)的特性冷蚂。
RandomAccessFile對(duì)象包含了一個(gè)記錄指針缭保,用以標(biāo)識(shí)當(dāng)前讀寫處的位置,當(dāng)程序新創(chuàng)建一個(gè)RandomAccessFile對(duì)象時(shí),該對(duì)象的文件指針記錄位于文件頭(也就是0處),當(dāng)讀/寫了n個(gè)字節(jié)后窗价,文件記錄指針將會(huì)后移n個(gè)字節(jié)矿筝。除此之外,RandomAccessFile還可以自由移動(dòng)該記錄指針。下面就是RandomAccessFile具有的兩個(gè)特殊方法,來(lái)操作記錄指針,實(shí)現(xiàn)隨機(jī)訪問(wèn):
long getFilePointer( ):返回文件記錄指針的當(dāng)前位置
void seek(long pos ):將文件指針定位到pos位置
三苞尝、RandomAccessFile的使用
利用RandomAccessFile實(shí)現(xiàn)文件的多線程下載,即多線程下載一個(gè)文件時(shí)宦芦,將文件分成幾塊宙址,每塊用不同的線程進(jìn)行下載。下面是一個(gè)利用多線程在寫文件時(shí)的例子调卑,其中預(yù)先分配文件所需要的空間抡砂,然后在所分配的空間中進(jìn)行分塊,然后寫入:
/**
* 測(cè)試?yán)枚嗑€程進(jìn)行文件的寫操作
*/
public class Test {
public static void main(String[] args) throws Exception {
// 預(yù)分配文件所占的磁盤空間恬涧,磁盤中會(huì)創(chuàng)建一個(gè)指定大小的文件
RandomAccessFile raf = new RandomAccessFile("D://abc.txt", "rw");
raf.setLength(1024*1024); // 預(yù)分配 1M 的文件空間
raf.close();
// 所要寫入的文件內(nèi)容
String s1 = "第一個(gè)字符串";
String s2 = "第二個(gè)字符串";
String s3 = "第三個(gè)字符串";
String s4 = "第四個(gè)字符串";
String s5 = "第五個(gè)字符串";
// 利用多線程同時(shí)寫入一個(gè)文件
new FileWriteThread(1024*1,s1.getBytes()).start(); // 從文件的1024字節(jié)之后開始寫入數(shù)據(jù)
new FileWriteThread(1024*2,s2.getBytes()).start(); // 從文件的2048字節(jié)之后開始寫入數(shù)據(jù)
new FileWriteThread(1024*3,s3.getBytes()).start(); // 從文件的3072字節(jié)之后開始寫入數(shù)據(jù)
new FileWriteThread(1024*4,s4.getBytes()).start(); // 從文件的4096字節(jié)之后開始寫入數(shù)據(jù)
new FileWriteThread(1024*5,s5.getBytes()).start(); // 從文件的5120字節(jié)之后開始寫入數(shù)據(jù)
}
// 利用線程在文件的指定位置寫入指定數(shù)據(jù)
static class FileWriteThread extends Thread{
private int skip;
private byte[] content;
public FileWriteThread(int skip,byte[] content){
this.skip = skip;
this.content = content;
}
public void run(){
RandomAccessFile raf = null;
try {
raf = new RandomAccessFile("D://abc.txt", "rw");
raf.seek(skip);
raf.write(content);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
raf.close();
} catch (Exception e) {
}
}
}
}
}
當(dāng)RandomAccessFile向指定文件中插入內(nèi)容時(shí)注益,將會(huì)覆蓋掉原有內(nèi)容。如果不想覆蓋掉溯捆,則需要將原有內(nèi)容先讀取出來(lái)丑搔,然后先把插入內(nèi)容插入后再把原有內(nèi)容追加到插入內(nèi)容后。