我學(xué) Java IO

說起來,我接觸 Java 是從大一下學(xué)期開始的,通過逐步學(xué)習(xí)接觸到了 Java IO 這個(gè)很重要的模塊,同時(shí)也是讓我很頭疼的一個(gè)模塊,好像一直都沒怎么學(xué)會(huì)。在我的腦子里,一直都是那種,這么多相關(guān)的類,怎么能記住啊。再加上,后來轉(zhuǎn)戰(zhàn) Android 就更少有直接使用 Java IO 去操作文件的機(jī)會(huì)。一個(gè)偶然的機(jī)會(huì),我學(xué)到了可以從另一種視角看 Java IO,突然覺得,Java IO,并不難。現(xiàn)在,我來記錄并分享一點(diǎn)自己的經(jīng)驗(yàn)。

如果是講操作文件的 API 的話,那估計(jì)得寫的老長,事實(shí)上,我對(duì) Java IO 相關(guān)的 API 并不太熟,而且我也不打算講。在這里我可能是從另一種我覺得是站在全局的角度去看 Java IO。

通常的,我們使用 Java IO 都是為了去對(duì)文件進(jìn)行操作,或讀或?qū)?。讀:從磁盤、網(wǎng)絡(luò)等渠道將文件內(nèi)容讀入到內(nèi)存中;寫:通過將內(nèi)存中的數(shù)據(jù)寫入到磁盤、網(wǎng)絡(luò)等進(jìn)行持久化保存。

Java Io

以前啊,我就光想著 Java IO 就是這么讀文件,寫文件,也沒什么的嘛。不就是對(duì)文件的操作嘛,沒什么可講的的,現(xiàn)在我不這么想了?,F(xiàn)在怎么想呢?我換了一種思路。

我們使用 Java IO 寫東西,寫的是什么?是字符串,字符串是什么?是字符數(shù)組組成的一種的對(duì)象,什么是字符?字符就是可以通過字節(jié)碼的形式表現(xiàn)出來一種東西。而字節(jié)碼就是 OutputStream 以及 InputStream 直接能進(jìn)行操作的東西,那什么是它們不是直接操作的?不就是字符串、字符數(shù)組嘛。可是我們?cè)趯懗绦虻臅r(shí)候,誰還記得這個(gè)字符串的字節(jié)碼是什么,那個(gè)字符的字節(jié)碼是啥。我們都是直接操作字符串以及少部分情況操作字符數(shù)組的。那怎么辦?

String To byte

有的人說,通過各種轉(zhuǎn)換就可以對(duì)應(yīng)的字節(jié)碼,然后進(jìn)行操作。事實(shí)上就是這樣的,Java 提供給我們的方法也是如此,通過各種轉(zhuǎn)換得到可以操作 String 或是字符數(shù)組,然后進(jìn)行操作。比如,OutputStreamWriter 就可以使用 OutputStreamWriter.write(String); 來直接操作字符串進(jìn)行寫入文件,還有通過 BufferedReader 就可以使用 String lineString = bufferedReader.readLine() 來直接進(jìn)行讀取一行文字。可是總一些我們可以從另一種角度看的東西。

仔細(xì)看一下,第二幅圖,沒什么啊,不就是數(shù)據(jù)在他們之間進(jìn)行轉(zhuǎn)換嗎,有什么的?是這樣的,但是還可以有另一種看法,字符串就是另種形式的字符數(shù)組,而字節(jié)數(shù)組就是另一種形式的字符數(shù)組。他們還是自己本身,只不過穿上了一件 “衣服” 而已。穿上了這身衣服,你以為他變了,從字符串 String 變成了字符數(shù)組 char[] 實(shí)際上,他還是 String ,只是不同的表現(xiàn)形態(tài)而已。沒有什么不同,他還是他,只是你需要看穿這件 “衣服”。

那你說,既然數(shù)據(jù)本身都沒有變化,只是穿了件衣服,那為什么 Java IO 的操作,顯得那么的麻煩?因?yàn)?,為了方便處理,也給處理過程穿上了衣服。OutputStream 只能處理字節(jié)數(shù)組,而包裹了一層 OutputStream 的 OutputStreamWriter 就能直接的操作 char[] 和 String。

好麻煩啊,就不能有一個(gè)直接能用來操作字符串的對(duì)象嗎,每回寫文件讀寫的時(shí)候,都得寫好幾個(gè)對(duì)象,煩死了。別煩啊,這樣做是有這樣做的理由的。就拿讀操作(InputStream)來說吧,我曾天真的以為讀操作只有一個(gè)來源就是,文件(FileInputStream)。后來才發(fā)現(xiàn),竟然有 ByteArrayInputStream、ObjectInputStream、PipedInputStream、StringBufferInputStream 等等(只列出部分,全部的都 在這 呢。他們分別處理字節(jié)數(shù)組、被序列化的對(duì)象、線程間的輸入流以及來自 StringBuffer 的輸入。對(duì)應(yīng)的還有寫操作(OutputStream)整體來說,雖然比 InputStream 少,但是也有好幾個(gè)呢,ByteArrayOutputStreamFileOutputStream、FilterOutputStreamObjectOutputStream、PipedOutputStream

如果這么多種輸入或是輸出方式,都要能處理 String、long、int 這種,或是再兼容一些其他方便我們程序員操作的方法,那類就太多了,想想一下,一個(gè) FileInputStream 就可能變成了 StringFileInputStream、LongFileInputStream、IntegerFileInputStream ,想想就覺得可怕。所以,Java 采用了穿 “衣服” 的形式,讓程序員通過對(duì)數(shù)據(jù)穿上不同的衣服,從而達(dá)到操作不同數(shù)據(jù)類型的效果。

image

FileInputStream 只能讀出字節(jié)數(shù)組,InputStreamReader 可以讀出字符數(shù)組,通過不同的對(duì)象進(jìn)行轉(zhuǎn)換,就能讀出或是寫出不同形式的數(shù)據(jù)。而且 FileInputStream 可以作為 InputStreamReader 的提供者,這樣的話,就能應(yīng)對(duì)足夠復(fù)雜的場(chǎng)景,只要給當(dāng)前的對(duì)象穿上另一件"衣服"就能搖身一變成為你想要的結(jié)果。

感覺很神奇啊,只要是 InputStream 相關(guān)的類,都可以作為生成下一個(gè) xxInputStream 對(duì)象輸入,只要是一個(gè) OutputStream 相關(guān)的類都可以作為生成下一個(gè) xxOutputStream 對(duì)象的輸入。其實(shí)啊,知道細(xì)節(jié)之后就不會(huì)覺得神奇了,只會(huì)覺得設(shè)計(jì)的很巧妙。

FilterOutputStreamFilterInputStream 這兩個(gè)是關(guān)鍵,他們倆分別繼承自 OutputStream 和 InputStream,同時(shí)又有非常多的子類,就是通過這些子類來實(shí)現(xiàn)各種轉(zhuǎn)換,什么線程的輸入做到輸出字符數(shù)組、被序列化的對(duì)象輸出字符串等等。

FilterOutputStream 子類:

  • BufferedOutputStream
  • CheckedOutputStream
  • CipherOutputStream
  • DataOutputStream
  • DeflaterOutputStream
  • DigestOutputStream
  • InflaterOutputStream
  • PrintStream

FilterInputStream 子類:

  • BufferedInputStream
  • CheckedInputStream
  • CipherInputStream
  • DataInputStream
  • DeflaterInputStream
  • DigestInputStream
  • InflaterInputStream
  • LineNumberInputStream
  • ProgressMonitorInputStream
  • PushbackInputStream

這些子類固然是很重要的,便于操作不同的數(shù)據(jù)類型,同樣重要的還有 Reader、Writer。這兩個(gè)類并不繼承 InputStream 與 OutputStream 但通過他們的子類,也同樣能實(shí)現(xiàn)更簡單的文件讀寫。比如 OutputStreamWriter、InputStreamReader。都可以直接對(duì) String 進(jìn)行操作。再搭配上 InputStream 和 OutputStream 那一大家子,真的是可以對(duì)文件可以為所欲為了。

對(duì)了,還一個(gè) Buffer,它直譯過來是緩沖的意思,干什么用的呢?是這樣的,磁盤的讀取或?qū)懭氲乃俣炔]有像直接操作內(nèi)存那樣快,所以需要一個(gè)緩沖的東西用來緩解雙方操作上的時(shí)間差,比如在寫的時(shí)候,可以先寫到緩沖區(qū),然后再把緩沖區(qū)的數(shù)據(jù)一點(diǎn)點(diǎn)寫到磁盤上。或者說,從磁盤讀數(shù)據(jù)的時(shí)候,先讀一些,讀到緩沖區(qū),等讀的東西,夠多了,然后再一起寫入到內(nèi)存中去。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容