原帖地址:http://www.tkk7.com/pengpenglin/archive/2010/03/03/314239.html#314399

【一】基于字節(jié)的輸入流


值得注意的地方有:

Level 2的輸入流,大多數(shù)都會(huì)指明數(shù)據(jù)源的形式:例如ByteArrayFilePiped

Level 3的輸入流,則不會(huì)出現(xiàn)具體的數(shù)據(jù)源名字,而是以功能取代:例如BufferedLineNumber

所以說Level 3的輸入流是對(duì)Level 2輸入流的“封裝和過濾”。實(shí)際上Level 2的輸入流,都繼承于一個(gè)叫做:FilterInputStream的輸入流。

下面是對(duì)各個(gè)input stream的簡介:

ByteArrayInputStream

從內(nèi)存中每次讀取一個(gè)字節(jié)的數(shù)據(jù),然后保存到內(nèi)置的緩沖區(qū)中。維持一個(gè)計(jì)數(shù)器用來記錄從數(shù)據(jù)源中讀入的字節(jié)數(shù)目。

調(diào)用該輸入流的close()方法不會(huì)產(chǎn)生任何實(shí)際的作用。因?yàn)樗?#8220;關(guān)閉”的對(duì)象是---內(nèi)存。而不是文件。不會(huì)拋出任何的IOException

FileInputStream

從文件系統(tǒng)中讀取原始的字節(jié)數(shù)據(jù)(raw bytes)。每次讀取一個(gè)字節(jié)

③PipedInputStream

管道輸入流,通常它的一端會(huì)和數(shù)據(jù)源連接,另一端和管道輸出流(PipedOutputStream) 連接。這樣從管輸入流讀入的任何數(shù)據(jù)將直接地傳輸?shù)焦艿垒敵隽鳌?br />
通常會(huì)有一個(gè)獨(dú)的線程從管道輸入流中讀取數(shù)據(jù),再交給另外一個(gè)線程,由另外的線程向管道輸出流中寫數(shù)據(jù)。如果使用單個(gè)線程進(jìn)行讀寫操作,很容易造成資源的死鎖。

SequenceInputStream

把多個(gè)輸入流按順序合并成一個(gè)輸入流

DataInputStream

從底層的其它字節(jié)輸入流中讀取字節(jié),然后轉(zhuǎn)換成與機(jī)器無關(guān)的原始類型數(shù)據(jù)(booleanbytechar)

BufferedInputStream

為底層的其它字節(jié)輸入流增加一個(gè)“緩沖”的功能,除此之外還可以“標(biāo)記”,“重置”輸入流。當(dāng)這個(gè)輸出流的對(duì)象被創(chuàng)建時(shí),一個(gè)內(nèi)置的緩沖區(qū)也就被創(chuàng)建了。

隨著底層的輸入流的不斷讀入,緩沖區(qū)中的數(shù)據(jù)也在不同刷新。一次性地從底層的輸入流讀入多個(gè)字節(jié),方便后續(xù)的轉(zhuǎn)碼工作


【二】基于字節(jié)的輸出流




值得注意的是
:

①在Level 2的輸出流,都是以功能來命名的。例如:PrintDataOutputBuffered

②在Level 3的輸出流,則多數(shù)都是以數(shù)據(jù)源的形式來命名的。例如:ByteArrayFilePiped

所以說Level 2的輸出流必須依賴于Level 3的輸出流,實(shí)際上Level 2的輸出流,都繼承與一個(gè)叫做FilterOutputStream的輸出流

下面是對(duì)各個(gè)output stream的簡介:

PrintStream

為底層的輸出流添加額外的功能,令到底層的輸出流可以方便地輸出各種經(jīng)過“格式化”的數(shù)據(jù)。和其它輸出流不同,該輸出流并不會(huì)拋出IOException,但是可以通過checkError方法來檢查是否有異常發(fā)生。

該輸出流具備自動(dòng)flush功能,但寫完一個(gè)字節(jié)數(shù)組,或者碰到一個(gè)println方法的調(diào)用,或者當(dāng)要寫出的字符是換行符時(shí)。會(huì)自動(dòng)清空flush

默認(rèn)情況下所有要寫出的內(nèi)存字符,都會(huì)被該輸出流以平臺(tái)默認(rèn)編碼方式,轉(zhuǎn)換為字節(jié)流輸出

DataOutputStream

允許應(yīng)用程序直接將基本類型數(shù)據(jù)(boolean, char, byte)直接寫出到底層的輸出流(內(nèi)部轉(zhuǎn)換為適當(dāng)?shù)淖止?jié))

BufferedOutputStream

為底層的輸出流提供“緩沖”的功能,所有的寫出請(qǐng)求和要寫出的數(shù)據(jù)都會(huì)先緩沖到該輸出流的緩沖區(qū)中,在適當(dāng)?shù)臅r(shí)機(jī)一次性寫出。

注意該類的write方法被調(diào)用時(shí)并不一定立即將內(nèi)存中的數(shù)據(jù)寫出到數(shù)據(jù)源,而可能先將數(shù)據(jù)緩存起來。

ByteArrayOutputStream

該輸出流能夠?qū)⒁獙懭雰?nèi)存的字節(jié),先緩存到自身的緩沖區(qū)中。并且該緩沖區(qū)的大小可以自動(dòng)增長。如果要從該輸出流中提取字節(jié),可以使用toByteArray,如果要還原為字符串,可以使用toString

關(guān)閉該輸出流并不會(huì)產(chǎn)生任何的IOException,因?yàn)樗妮敵龆耸?/span>---內(nèi)存而非文件。

FileOutputStream

該輸出流以原始字節(jié)(raw bytes)的方式向底層文件系統(tǒng)中寫數(shù)據(jù)。在某些系統(tǒng)下,有時(shí)候只允許同一個(gè)文件

打開一個(gè)輸出流。所以如果該文件已經(jīng)被打開了,則再次打開一個(gè)輸出流會(huì)拋出異常。


【三】基于字符的輸入流


值得注意的地方有:

Level 2的輸入流,大多數(shù)都會(huì)指明數(shù)據(jù)源的形式:例如CharArrayStringFile

Level 3的輸入流,則不會(huì)在出現(xiàn)具體的數(shù)據(jù)源名字,而是以功能取代:例如BufferedLineNumber

但是和基于字節(jié)的輸入流結(jié)構(gòu)不同,FileInputStream是直接繼承于InputStream類的。但是FileReader卻是繼承與InputStreamReader的。而且BufferedReader不是繼承于FilterReader。看看下面的結(jié)構(gòu):

java.io.Reader (implements java.io.Closeable, java.lang.Readable)

     java.io.BufferedReader

          java.io.LineNumberReader

     java.io.CharArrayReader

     java.io.FilterReader

          java.io.PushbackReader

     java.io.InputStreamReader

          java.io.FileReader

     java.io.PipedReader

     java.io.StringReader

這時(shí)為什么呢?其實(shí)如果我們知道InputStreamReader的作用是什么就知道了:它的作用是充當(dāng)一座基于字節(jié)流和字符流之間轉(zhuǎn)換的橋梁。它將從字節(jié)流讀取的字節(jié)按照編碼轉(zhuǎn)換成字符。

實(shí)際上任何對(duì)文件的IO讀寫,最終都是以字節(jié)的形式進(jìn)行的。所以讀取字符只不過是一種邏輯上的說法,那么FileReader為什么繼承于InputStreamReader就可以理解了。

下面是對(duì)各個(gè)Reader的介紹:

CharArrayReader

直接從內(nèi)存中以“字符”的形式讀取數(shù)據(jù)。每次讀取一個(gè)字符,存放到緩存區(qū)中。

FileReader

從文本文件中讀取字符的字符輸入流,該字符輸入流使用系統(tǒng)默認(rèn)的字符集編碼和緩存區(qū)大小,不能更改。如果需要重新調(diào)整輸入流的編碼,必須使用InputStreamReader

StringReader

從一個(gè)字符串中讀取內(nèi)容

BufferedReader

為其它的基于字符的輸入流提供緩沖功能以提高效率。通常情況下,對(duì)于底層輸入流的任何一次read或者readLine請(qǐng)求都將導(dǎo)致直接的磁盤訪問,這將導(dǎo)致效率非常地下。

當(dāng)使用緩存的字符輸入流時(shí),讀取請(qǐng)求將被緩存,在合適的時(shí)候一次性讀入批量數(shù)據(jù),再進(jìn)行編碼轉(zhuǎn)換。以此顯著提高效率。這個(gè)緩存輸入流的緩沖區(qū)大小是可以指定的。

LineNumberReader

可以跟蹤讀入的“行數(shù)據(jù)”的字符輸入流。該輸入流內(nèi)置一個(gè)指示器,用于跟蹤讀入的數(shù)據(jù)的行數(shù)。默認(rèn)情況下行號(hào)從0開始。用戶可以通過setLineNumbergetLineNumber來設(shè)置/或者行號(hào)。一個(gè)行可以由“換行符”,“回車符”,“回車換行符”標(biāo)識(shí)。當(dāng)遇到其中任意一個(gè)符號(hào)時(shí),指示器的值將增加1。

注意的是:setLineNumber方法并不會(huì)真正地改變數(shù)據(jù)在文件中的物理位置,而是簡單地修改了指示器的數(shù)值而已。


【四】基于字符的輸出流



值得注意的是:  

①在Level 2的輸出流,都是以功能來命名的。例如:PrintBuffered

②在Level 3的輸出流,則多數(shù)都是以數(shù)據(jù)源的形式來命名的。例如:CharArrayFileString

所以說Level 2的輸出流必須依賴于Level 3的輸出流,實(shí)際上Level 2的輸出流,都繼承與一個(gè)叫做FilterWriter的輸出流

PrintWriter

將對(duì)象數(shù)據(jù)以恰當(dāng)?shù)母袷捷敵龅轿谋据敵隽鳎?/span>PrintOutputStream類不同,后者當(dāng)碰到換行符的時(shí)候會(huì)清空緩沖區(qū)。但是PrintWriter不會(huì),它只在print方法被調(diào)用時(shí)才會(huì)清空緩存。所以理論上來說它要比PrintOutputStream更加高效,因?yàn)橹灰彌_區(qū)允許,它可以接納更多的內(nèi)容而一次性寫入到文件。

這個(gè)類使用系統(tǒng)默認(rèn)的行分割符來代替“換行符"n”,因?yàn)椴皇撬械南到y(tǒng)都是通過“"n”來換行的。

BufferedWriter

為其它字符輸出流提供緩沖功能,該輸出流的緩沖區(qū)大小可以設(shè)置,否則將使用默認(rèn)的緩沖區(qū)大小。這個(gè)類有一個(gè)newLine方法,用于返回一個(gè)基于系統(tǒng)的行分割符,而非一定是“"n”。這個(gè)類會(huì)緩存寫請(qǐng)求,當(dāng)要寫出的字符達(dá)到一定程度時(shí)就一次性地寫出到底層的文件輸出流。

CharArrayWriter

類似于ByteArrayOutputStream,向內(nèi)存中寫字符。其中內(nèi)置一個(gè)緩沖區(qū),大小可以動(dòng)態(tài)增長。如果要得到寫入的字符可以使用toCharArray方法,如果要構(gòu)造出字符串則可以使用toString方法。

FileWriter

以基于字符的方式向文件中寫數(shù)據(jù)。該輸出流使用系統(tǒng)平臺(tái)默認(rèn)的字符集編碼方式和緩存區(qū)大小,不能設(shè)置改變。如果需要的話可以使用OutputStreamWriter。

某些系統(tǒng)只允許同一時(shí)刻一個(gè)文件被一個(gè)輸出流打開,所以假如文件已經(jīng)被另外的輸出流打開了,那么新的輸出流試圖打開同一個(gè)文件時(shí)將拋出異常。


【五】字節(jié)流和字符流之間的轉(zhuǎn)換



①InputStreamReader:

將字節(jié)流--》字符流,默認(rèn)使用系統(tǒng)編碼,可另外指定編碼方式。是一個(gè)解碼過程

   new BufferedReader(new InputStreamReader(System.in))

②OutputStreamWriter:

將字符流--》字節(jié)流,默認(rèn)使用系統(tǒng)編碼,可另外指定編碼方式。是一個(gè)編碼過程
   new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out));