原帖地址:http://www.tkk7.com/pengpenglin/archive/2010/03/03/314239.html#314399
【一】基于字節的輸入流
值得注意的地方有:
①Level 2的輸入流,大多數都會指明數據源的形式:例如ByteArray,File,Piped
②Level 3的輸入流,則不會出現具體的數據源名字,而是以功能取代:例如Buffered,LineNumber
所以說Level 3的輸入流是對Level 2輸入流的“封裝和過濾”。實際上Level 2的輸入流,都繼承于一個叫做:FilterInputStream的輸入流。
下面是對各個input stream的簡介:
①ByteArrayInputStream
從內存中每次讀取一個字節的數據,然后保存到內置的緩沖區中。維持一個計數器用來記錄從數據源中讀入的字節數目。
調用該輸入流的close()方法不會產生任何實際的作用。因為它“關閉”的對象是---內存。而不是文件。不會拋出任何的IOException。
②FileInputStream
從文件系統中讀取原始的字節數據(raw bytes)。每次讀取一個字節
③PipedInputStream
管道輸入流,通常它的一端會和數據源連接,另一端和管道輸出流(PipedOutputStream) 連接。這樣從管輸入流讀入的任何數據將直接地傳輸到管道輸出流。
通常會有一個獨的線程從管道輸入流中讀取數據,再交給另外一個線程,由另外的線程向管道輸出流中寫數據。如果使用單個線程進行讀寫操作,很容易造成資源的死鎖。
④SequenceInputStream
把多個輸入流按順序合并成一個輸入流
⑤DataInputStream
從底層的其它字節輸入流中讀取字節,然后轉換成與機器無關的原始類型數據(boolean,byte,char)
⑥BufferedInputStream
為底層的其它字節輸入流增加一個“緩沖”的功能,除此之外還可以“標記”,“重置”輸入流。當這個輸出流的對象被創建時,一個內置的緩沖區也就被創建了。
隨著底層的輸入流的不斷讀入,緩沖區中的數據也在不同刷新。一次性地從底層的輸入流讀入多個字節,方便后續的轉碼工作
【二】基于字節的輸出流

值得注意的是:
①在Level 2的輸出流,都是以功能來命名的。例如:Print,DataOutput,Buffered
②在Level 3的輸出流,則多數都是以數據源的形式來命名的。例如:ByteArray,File,Piped
所以說Level 2的輸出流必須依賴于Level 3的輸出流,實際上Level 2的輸出流,都繼承與一個叫做FilterOutputStream的輸出流
下面是對各個output stream的簡介:
①PrintStream
為底層的輸出流添加額外的功能,令到底層的輸出流可以方便地輸出各種經過“格式化”的數據。和其它輸出流不同,該輸出流并不會拋出IOException,但是可以通過checkError方法來檢查是否有異常發生。
該輸出流具備自動flush功能,但寫完一個字節數組,或者碰到一個println方法的調用,或者當要寫出的字符是換行符時。會自動清空flush。
默認情況下所有要寫出的內存字符,都會被該輸出流以平臺默認編碼方式,轉換為字節流輸出
②DataOutputStream
允許應用程序直接將基本類型數據(boolean, char, byte)直接寫出到底層的輸出流(內部轉換為適當的字節)
③BufferedOutputStream
為底層的輸出流提供“緩沖”的功能,所有的寫出請求和要寫出的數據都會先緩沖到該輸出流的緩沖區中,在適當的時機一次性寫出。
注意該類的write方法被調用時并不一定立即將內存中的數據寫出到數據源,而可能先將數據緩存起來。
④ByteArrayOutputStream
該輸出流能夠將要寫入內存的字節,先緩存到自身的緩沖區中。并且該緩沖區的大小可以自動增長。如果要從該輸出流中提取字節,可以使用toByteArray,如果要還原為字符串,可以使用toString。
關閉該輸出流并不會產生任何的IOException,因為它的輸出端是---內存而非文件。
⑤FileOutputStream
該輸出流以原始字節(raw bytes)的方式向底層文件系統中寫數據。在某些系統下,有時候只允許同一個文件
打開一個輸出流。所以如果該文件已經被打開了,則再次打開一個輸出流會拋出異常。
【三】基于字符的輸入流
值得注意的地方有:
①Level 2的輸入流,大多數都會指明數據源的形式:例如CharArray,String,File
②Level 3的輸入流,則不會在出現具體的數據源名字,而是以功能取代:例如Buffered,LineNumber
但是和基于字節的輸入流結構不同,FileInputStream是直接繼承于InputStream類的。但是FileReader卻是繼承與InputStreamReader的。而且BufferedReader不是繼承于FilterReader。看看下面的結構:
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
這時為什么呢?其實如果我們知道InputStreamReader的作用是什么就知道了:它的作用是充當一座基于字節流和字符流之間轉換的橋梁。它將從字節流讀取的字節按照編碼轉換成字符。
實際上任何對文件的IO讀寫,最終都是以字節的形式進行的。所以讀取”字符”只不過是一種邏輯上的說法,那么FileReader為什么繼承于InputStreamReader就可以理解了。
下面是對各個Reader的介紹:
①CharArrayReader
直接從內存中以“字符”的形式讀取數據。每次讀取一個字符,存放到緩存區中。
②FileReader
從文本文件中讀取字符的字符輸入流,該字符輸入流使用系統默認的字符集編碼和緩存區大小,不能更改。如果需要重新調整輸入流的編碼,必須使用InputStreamReader。
③StringReader
從一個字符串中讀取內容
④BufferedReader
為其它的基于字符的輸入流提供緩沖功能以提高效率。通常情況下,對于底層輸入流的任何一次read或者readLine請求都將導致直接的磁盤訪問,這將導致效率非常地下。
當使用緩存的字符輸入流時,讀取請求將被緩存,在合適的時候一次性讀入批量數據,再進行編碼轉換。以此顯著提高效率。這個緩存輸入流的緩沖區大小是可以指定的。
⑤LineNumberReader
可以跟蹤讀入的“行數據”的字符輸入流。該輸入流內置一個指示器,用于跟蹤讀入的數據的行數。默認情況下行號從0開始。用戶可以通過setLineNumber和getLineNumber來設置/或者行號。一個行可以由“換行符”,“回車符”,“回車換行符”標識。當遇到其中任意一個符號時,指示器的值將增加1。
注意的是:setLineNumber方法并不會真正地改變數據在文件中的物理位置,而是簡單地修改了指示器的數值而已。
【四】基于字符的輸出流

值得注意的是:
①在Level 2的輸出流,都是以功能來命名的。例如:Print,Buffered
②在Level 3的輸出流,則多數都是以數據源的形式來命名的。例如:CharArray,File,String
所以說Level 2的輸出流必須依賴于Level 3的輸出流,實際上Level 2的輸出流,都繼承與一個叫做FilterWriter的輸出流
①PrintWriter
將對象數據以恰當的格式輸出到文本輸出流,和PrintOutputStream類不同,后者當碰到換行符的時候會清空緩沖區。但是PrintWriter不會,它只在print方法被調用時才會清空緩存。所以理論上來說它要比PrintOutputStream更加高效,因為只要緩沖區允許,它可以接納更多的內容而一次性寫入到文件。
這個類使用系統默認的行分割符來代替“換行符"n”,因為不是所有的系統都是通過“"n”來換行的。
②BufferedWriter
為其它字符輸出流提供緩沖功能,該輸出流的緩沖區大小可以設置,否則將使用默認的緩沖區大小。這個類有一個newLine方法,用于返回一個基于系統的行分割符,而非一定是“"n”。這個類會緩存寫請求,當要寫出的字符達到一定程度時就一次性地寫出到底層的文件輸出流。
③CharArrayWriter
類似于ByteArrayOutputStream,向內存中寫字符。其中內置一個緩沖區,大小可以動態增長。如果要得到寫入的字符可以使用toCharArray方法,如果要構造出字符串則可以使用toString方法。
④FileWriter
以基于字符的方式向文件中寫數據。該輸出流使用系統平臺默認的字符集編碼方式和緩存區大小,不能設置改變。如果需要的話可以使用OutputStreamWriter。
某些系統只允許同一時刻一個文件被一個輸出流打開,所以假如文件已經被另外的輸出流打開了,那么新的輸出流試圖打開同一個文件時將拋出異常。
【五】字節流和字符流之間的轉換

①InputStreamReader:
將字節流--》字符流,默認使用系統編碼,可另外指定編碼方式。是一個解碼過程
new BufferedReader(new InputStreamReader(System.in))
②OutputStreamWriter:
將字符流--》字節流,默認使用系統編碼,可另外指定編碼方式。是一個編碼過程
new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out));