RandomAccessFile简介与使用
今兒翻閱jdk源碼的時(shí)候,無意間發(fā)現(xiàn)了RandomAccessFile這個(gè)類,從來沒見過,也沒使用過,帶著好奇心,我決定深入了解一下這個(gè)類的意義和使用方法。
從字面意思來看這個(gè):隨機(jī) 通行 文件
其實(shí)個(gè)人感覺就是:
一款功能較豐富的文本編輯工具
話不多說,讓我們先一探究竟,初步了解這個(gè)類的設(shè)計(jì)理念
目錄
一、api的研究
曾經(jīng)的我們?nèi)绾翁幚砦谋?/p>
RandomAccessFile類幫我們處理文本
二、實(shí)際操作一下吧
三、對該工具類的價(jià)值分析
一、api的研究
曾經(jīng)的我們?nèi)绾翁幚砦谋?/h3>
以前我們要處理一個(gè)文件會(huì)怎么做?是不是如下圖所示:
上面是讀取文件的方式,寫文件也一樣,我們需要使用輸出流,如下圖所示:
ok 看到這里想必大家都會(huì)發(fā)現(xiàn),我對一個(gè)文件的讀寫操作需要new兩個(gè)類,分別是讀流和寫流,并且他們的方法并不多
RandomAccessFile類幫我們處理文本
首先觀察構(gòu)造器:
可以發(fā)現(xiàn)這里定義了四種模式:R RW RWD RWS
| r | 以只讀的方式打開文本,也就意味著不能用write來操作文件 |
| rw | 讀操作和寫操作都是允許的 |
| rws | 每當(dāng)進(jìn)行寫操作,同步的刷新到磁盤,刷新內(nèi)容和元數(shù)據(jù) |
| rwd | 每當(dāng)進(jìn)行寫操作,同步的刷新到磁盤,刷新內(nèi)容 |
下面讓我們看看RandomAccessFile為我們提供的方法:
| 可以看出: 這個(gè)類集中了豐富的讀寫方法 下面我舉幾個(gè)比較典型的方法來說明一下這個(gè)類的強(qiáng)大之處 ============================================ 1、seek:指定文件的光標(biāo)位置,通俗點(diǎn)說就是指定你的光標(biāo)位置 然后下次讀文件數(shù)據(jù)的時(shí)候從該位置讀取。 ============================================ 2、getFilePointer:我們注意到這是一個(gè)long類型的返回值, 字面意思就是返回當(dāng)前的文件光標(biāo)位置。 這樣方便我們后面讀取插入。 ============================================ 3、length:毫無疑問的方法,文件的長度,返回long類型。 注意它并不會(huì)受光標(biāo)的影響。只會(huì)反應(yīng)客觀的文本長度。 ============================================ 4、read()、read(byte[] b)、read(byte[] b,int off,int len) 這些方法跟readstream中的方法一樣, 例如最后一個(gè):定義緩沖數(shù)組,從數(shù)組的off偏移量位置開始寫, 讀取轉(zhuǎn)換為數(shù)組數(shù)據(jù)達(dá)到len個(gè)字節(jié)。 總之這是一個(gè)讀文件內(nèi)容的標(biāo)準(zhǔn)操作api。 ============================================ 5、readDouble() readFloat() readBoolean() readInt() readLong() readShort() readByte() readChar() 這些方法都是去read每一個(gè)字符,個(gè)人感覺就是返回他們的ASCII碼 當(dāng)然如果專家們有異議可以指出,我測試的時(shí)候至少是這么感覺得。 大家也可以自己試一下。 比如readLong就是要求你的文本內(nèi)容必須有八個(gè)字符,不然會(huì)報(bào)錯(cuò)。 伴隨著也就是 writeDouble() writeFloat() writeBoolean() writeInt() writeLong() writeShort() writeByte() writeChar() ============================================ 6、readFully(byte[] b): 這個(gè)方法的作用就是將文本中的內(nèi)容填滿這個(gè)緩沖區(qū)b。 如果緩沖b不能被填滿,那么讀取流的過程將被阻塞, 如果發(fā)現(xiàn)是流的結(jié)尾,那么會(huì)拋出異常。 這個(gè)過程就比較像“湊齊一車人在發(fā)車,不然不走”。 ============================================ 7、getChannel:它返回的就是nio通信中的file的唯一channel ============================================ 8、skipBytes(int n):跳過n字節(jié)的位置,相對于當(dāng)前的point。 ? ? |
可以看出RandomAccessFile實(shí)現(xiàn)了大部分文件輸入輸出流的方法,但是底層實(shí)現(xiàn)中他實(shí)現(xiàn)的是DataInput和DataOutput接口,并非是FileInputStream和FileOutputStream。RandomAccessFile使用很多native方法實(shí)現(xiàn)了對文件的操作,并且很多native方法跟inputstream都有重疊,比如read0方法。我想這么做可能是為了讓這個(gè)DataInput接口的職責(zé)更明確吧。
?
從上述對比中可以看出,datainput更注視強(qiáng)化對數(shù)據(jù)的各種既定操作。并沒有出現(xiàn)類似inputstream的方法,也許這就是我們常說的單一職責(zé)原則吧。
二、實(shí)際操作一下吧
定義一個(gè)文件
編寫一個(gè)方便我們使用的工廠類:
public class RAFTestFactory private static final String url = "D:\\EclipseWorkspace\\text\\test.txt";private static final String [] model = {"r","rw","rws","rwd"};public static RandomAccessFile getRAFWithModelR() throws FileNotFoundException {RandomAccessFile raf = new RandomAccessFile(new File(url), model[0]);return raf;}public static RandomAccessFile getRAFWithModelRW() throws FileNotFoundException {RandomAccessFile raf = new RandomAccessFile(new File(url), model[1]);return raf;}public static RandomAccessFile getRAFWithModelRWS() throws FileNotFoundException {RandomAccessFile raf = new RandomAccessFile(new File(url), model[2]);return raf;}public static RandomAccessFile getRAFWithModelRWD() throws FileNotFoundException {RandomAccessFile raf = new RandomAccessFile(new File(url), model[3]);return raf;} }編寫測試類1:
?
public class RAFTestMain {public static void main(String[] args) throws IOException {RandomAccessFile raf = RAFTestFactory.getRAFWithModelR();System.out.println("raf.length()->獲取文本內(nèi)容長度:"+raf.length());System.out.println("raf.getFilePointer()->獲取文本頭指針:"+raf.getFilePointer());raf.seek(4);System.out.println("raf.getFilePointer()->第二次獲取文本頭指針:"+raf.getFilePointer());} }?
看一下結(jié)果,體驗(yàn)一下seek的含義
raf.length()->獲取文本內(nèi)容長度:9
raf.getFilePointer()->獲取文本頭指針:0
raf.getFilePointer()->第二次獲取文本頭指針:4
?
編寫測試類2:
?
public class RAFTestMain {public static void main(String[] args) throws IOException {RandomAccessFile raf = RAFTestFactory.getRAFWithModelR();raf.write(1);} }?
為什么出現(xiàn)這個(gè)結(jié)果,就是因?yàn)槲覀兪褂昧?R model,也就是只讀模式,這是寫入會(huì)報(bào)錯(cuò)。
編寫測試類3:
? public class RAFTestMain {public static void main(String[] args) throws IOException {RandomAccessFile raf = RAFTestFactory.getRAFWithModelRW();String word = "ljh";raf.write(word.getBytes());} }?
可以看到我們寫的位置就是當(dāng)前光標(biāo)的位置,這個(gè)時(shí)候讓我們結(jié)合seek和write試驗(yàn)一下吧。
編寫測試類4:
? public class RAFTestMain {public static void main(String[] args) throws IOException {RandomAccessFile raf = RAFTestFactory.getRAFWithModelRW();raf.seek(4);String word = "ljh";raf.write(word.getBytes());} }?
看,此時(shí)我們很方便的實(shí)現(xiàn)了插入操作。這是其他類無法實(shí)現(xiàn)的功能。也是這個(gè)類的強(qiáng)大之處。
?
編寫測試類5:
最后我們看看
readDouble() readFloat() readBoolean() readInt() readLong() readShort() readByte() readChar()
writeDouble() writeFloat() writeBoolean() writeInt() writeLong() writeShort() writeByte() writeChar()
他們都怎么用的
? public class RAFTestMain {public static void main(String[] args) throws IOException {RandomAccessFile raf = RAFTestFactory.getRAFWithModelRW();raf.writeByte(3);raf.writeChar('a');raf.writeShort(5);raf.writeInt(6);raf.writeLong(792929347162343l);raf.writeFloat(8.5f);raf.writeDouble(9.44d);raf.writeBoolean(true);} }?
真是仙的不行,反正我是看不出個(gè)所以然。
?
三、對該工具類的價(jià)值分析
1、大型文本日志類文件的快速定位獲取數(shù)據(jù):
得益于seek的巧妙設(shè)計(jì),我認(rèn)為我們可以從超大的文本中快速定位我們的游標(biāo),例如每次存日志的時(shí)候,我們可以建立一個(gè)索引緩存,索引是日志的起始日期,value是文本的poiniter 也就是光標(biāo),這樣我們可以快速定位某一個(gè)時(shí)間段的文本內(nèi)容
2、并發(fā)讀寫
emmm也是得益于seek的設(shè)計(jì),我認(rèn)為多線程可以輪流操作seek控制光標(biāo)的位置,從未達(dá)到不同線程的并發(fā)寫操作。
3、更方便的獲取二進(jìn)制文件
通過自帶的讀寫轉(zhuǎn)碼(readDouble、writeLong等),我認(rèn)為可以快速的完成字節(jié)碼到字符的轉(zhuǎn)換功能,對使用者來說比較友好。
?
后續(xù)如果自己有想法,多做實(shí)驗(yàn),多看源碼。ok太晚了 睡覺了。。。
總結(jié)
以上是生活随笔為你收集整理的RandomAccessFile简介与使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 将文件转为stream流_NIO之文件I
- 下一篇: 我的博客即将同步至腾讯云+社区