JavaIo:JavaIo輸入輸出流

轉(zhuǎn)載至“http://segmentfault.com/a/1190000003817055?utm_source=Weibo&utm_medium=shareLink&utm_campaign=socialShare”

流的原理:

一連串有順序的數(shù)據(jù)系列可以看成是一個流。

輸入輸出流:


? ? ?數(shù)據(jù)從IO輸入到程序的流是輸入流,數(shù)據(jù)從程序輸出到IO的流是輸出流。

下面我們使用字節(jié)輸入輸出流來說明這個問題:

1.輸入流 InputStream一般是由javaio對象(如File)建立的,當新建一個InputStream時,io對象建立了一個包含有數(shù)據(jù)的管道(其實就是我們所說的這個“流”)并將io對象存儲的數(shù)據(jù)輸入(input)到管道中,因此管道里的數(shù)據(jù)流就是io對象內(nèi)的數(shù)據(jù)。當調(diào)用InputStream數(shù)據(jù)流的read方法時,管道里的數(shù)據(jù)流讀出到內(nèi)存對象中(比如數(shù)組或者字符串),注意,讀出的比特流將會被移除,具體能可讀的數(shù)據(jù)的量可用available函數(shù)來查看;

2.輸出流 OutputStream也是由javaio對象(如File)建立的,當新建一個OutputStream時,io對象建立了一個包含有數(shù)據(jù)流的管道并建立起io對象和管道的映射。 當調(diào)用OutputStream數(shù)據(jù)流的write方法時,內(nèi)存對象里的數(shù)據(jù)就會流入管道里,而管道里的數(shù)據(jù)流輸出(output)到io對象中,flush函數(shù)將促使數(shù)據(jù)緩沖區(qū)中的數(shù)據(jù)被寫入到io設備(文件本身)中區(qū);


在這個例子里我們可以充分看出輸入流創(chuàng)建和輸入的過程,首先創(chuàng)建一個File對象來映射IO上的這個文件,依據(jù)這個File對象來創(chuàng)建輸入流InputStream對象,注意,創(chuàng)建過后輸入流里按序存儲著IO文件里的數(shù)據(jù)內(nèi)容(這個過程中可能InputStream并不是其存儲作用的,因為若果這樣大文件內(nèi)的數(shù)據(jù)一次性存儲可能會爆內(nèi)存,所以這個過程應該是InputStream映射到IO文件),調(diào)用輸入流InputStream對象的read方法,即可將流內(nèi)的數(shù)據(jù)輸入到程序中的之前創(chuàng)建的對象內(nèi),最終在使用完后關閉作為有限資源的輸入流。這個過程完成了數(shù)據(jù)由IO對象輸入到程序。

注意:如果是上次沒有讀完輸入流內(nèi)的內(nèi)容,那么下一次程序到InputStream去讀的時候是接著上次的結尾讀的,這個可以根據(jù)InputStream對象的available方法看出來,所以在這個角度來看輸入流就像是文件里的索引指針一樣。


在這個例子里我們可以充分看出輸出流創(chuàng)建和輸出的過程,首先創(chuàng)建一個File對象來映射IO上的這個文件,依據(jù)這個File對象來創(chuàng)建輸出流OutputStream對象,調(diào)用輸出流OutputStream對象的write方法,即可將程序?qū)ο笾械臄?shù)據(jù)寫到輸出流中然后從輸出流輸出到IO文件中去,最終在使用完后關閉作為有限資源的輸出流。這個過程完成了數(shù)據(jù)由程序輸出到IO文件中。

字符輸入輸出流的道理是一樣的,只不過字符流是直接處理字符的,而字節(jié)流的處理單位是字節(jié)。read和write的API大同小異,無非就是把流里面的內(nèi)容和緩沖區(qū)通過這些函數(shù)來進行交換。

流的流:

既然可以依據(jù)IO文件來創(chuàng)建流在文件和程序之間交換數(shù)據(jù),那么我們可不可以從中間再加入一個流來作為中轉(zhuǎn)處理一下數(shù)據(jù)呢?這個流的流構成的多流鏈稱之為“流對象鏈”,這個過程說明不是所有的流都是直接和原始數(shù)據(jù)源打交道的,所以有如下定義:

節(jié)點流(Node Stream)直接連接到數(shù)據(jù)源,直接從IO文件上輸入或輸出數(shù)據(jù);

處理流(Processing Stream)是對一個已存在的流的連接和封裝,通過所封裝的流的功能調(diào)用實現(xiàn)增強的數(shù) 據(jù)讀寫功能,它并不直接連到數(shù)據(jù)源。


這個過程的原理如下圖所示:

在這個例子里我們可以充分看出流對象鏈形成的過程,首先創(chuàng)建一個File對象來映射IO上的這個文件,依據(jù)這個File對象來創(chuàng)建輸出流OutputStream對象,利用這個輸出流對象再創(chuàng)建一個PrintStream對象來鏈接輸出流對象,調(diào)用PrintStream對象的print方法,即可將程序?qū)ο笾械臄?shù)據(jù)寫到PrintStream中然后再輸出到IO文件中去,最終在使用完后關閉作為有限資源的流。這個過程完成了數(shù)據(jù)由程序輸出到IO文件中。


流中的緩沖技術

在內(nèi)存中開辟一塊區(qū)域,稱為緩沖區(qū),當緩沖區(qū)滿時一次寫入到磁盤中,提高了I/O的性能。和一般的輸入輸出流相比,這樣的帶有緩沖區(qū)的流可以做到更好的IO性能,在帶緩沖的輸出流時由于緩沖區(qū)的存在,需要在最后強制使用flush函數(shù)將緩沖區(qū)中剩余的內(nèi)容全部輸出到IO設備中去。


這里表現(xiàn)的是這個過程,IO文件里的數(shù)據(jù)經(jīng)過文件輸入流FileInputStream對象流入緩沖輸入流BufferedInputStream對象,之后所有的數(shù)據(jù)(在數(shù)據(jù)量較小的時候,一般是小于8K時,后面會討論到)流入輸入流的緩沖區(qū),之后每次在讀取的時候都是直接從緩沖區(qū)讀到臨時的數(shù)組中去而不是再從流讀入,然后臨時數(shù)組的數(shù)據(jù)在write函數(shù)的作用下寫到輸出流的緩沖區(qū)中去,緩沖區(qū)滿后數(shù)據(jù)會經(jīng)由緩沖輸出流BufferedOutputStream對象流入文件輸出流FileOutputStream對象,并最終輸出到IO文件中去,如果緩沖區(qū)不滿的話是不會自發(fā)輸出到緩沖輸出流中去的,因此往往我們需要在最后緩沖區(qū)不滿的情況下強制執(zhí)行輸出流的flush方法讓緩沖區(qū)數(shù)據(jù)強制輸出到輸出流中去。這個過程完成了IO文件數(shù)據(jù)的流轉(zhuǎn),中間有一個緩沖區(qū)在暫存數(shù)據(jù)。


在這個例子里我們可以更容易地發(fā)現(xiàn)BufferedReader這樣的緩沖類輸入流的緩沖作用,當首次調(diào)用readline(或者read等各種讀取方法)函數(shù)讀取這個輸入流的時候,就會將流里的數(shù)據(jù)讀進程序為BufferedInputStream對象分配的一個緩沖區(qū)中,而在此后的讀取輸入流的過程中就不需要去流中讀取而只需要去緩沖區(qū)里讀取就可以了,將開銷較大的IO數(shù)據(jù)交換過程變成了開銷小得多的內(nèi)存數(shù)據(jù)交換,進而提高了IO效率,這是緩沖輸入輸出流的好處。但是這個緩沖區(qū)的大小是有限的,jdk為這個大小確定的固定值為8K字節(jié),一旦超過這個值的話在第一次讀取時就只能緩沖最多8K子節(jié)的數(shù)據(jù),超出的部分只能在之后再緩沖。最后,如果要結束任務寫入輸出流的時候,要注意調(diào)用輸出流的flush方法來將緩沖區(qū)強制清空使之全部輸出到輸出流中去。


上面這個過程演示了緩沖區(qū)的大小,當輸入流的內(nèi)容填不滿緩沖區(qū)時(也就是不足8192字節(jié)時),如果不用flush沒有辦法自動寫入文件,當原來緩沖區(qū)的大小大于這個值的時候,會一次性把上次的8192字節(jié)自動寫入,下一次會再讀入8192個字節(jié),完成上面的過程。因此,這提醒我們,使用帶有緩沖的輸出流時務必要在最后強制清空緩沖進入輸出流才能保證數(shù)據(jù)不出錯。

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

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

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