[三]JavaIO之IO體系類整體設計思路 流的概念以及四大基礎分類


從本文開始,將正式進入JavaIO的簡介
在繼續javaIO系列的文章之前
可以過去看一下 本人博客上的設計模式中的 適配器模式和裝飾器模式
這會對接下來的閱讀大有幫助
 
本文是從邏輯上介紹整個的Java IO類家譜畫像.
 

1.流

 
計算機以及互聯網的世界發展不過短短幾十年,但是這幾十年卻是日新月異
系統的復雜度也越來越高,程序設計語言的抽象程度也越來越高
但是無論如何都繞不開一個話題,那就是IO
之前已經介紹過,IO 就是輸入 和 輸出, 入和出是相對於應用程序來說的
而且,經常一個程序的輸出可能是另一個程序的輸入
這本身就是一個抽象的概念
並沒有"必須怎么樣,那才叫IO"的說法
從數據庫,從文件,從內存,從網絡拿數據,你都可以叫做輸入,數據寫出,都可以叫做輸出,這並沒有什么好糾結的
 
在java中使用流這一概念來描述輸入和輸出

流的字面含義

image_5b94b200_4459
百度百科中是這樣描述流的, 可以看得出來 , 流本身就包含了 這樣一層含義 
物質      一個地方      流向了      另一個地方
 
在繼續之前,我們先回想下放暑假或者開學時候的場景
假定你需要做汽車和火車,如下圖所示
image_5b94b200_4484
 
上圖中有幾個關鍵概念
主體 人     人從一個地方到了另一個地方
源/目的      學校/家
方向 回家或者返校       圖中的兩個箭頭
中間形式 火車和汽車

1.1流到底是什么

 
我們再舉一個比較簡單的例子, 使用 水管 往桶里面加水或者抽水
 
源/主體內容/方向
水桶, 作為一個容器,他就是  源
里面可能裝了水,也可能裝了酒,還可能裝了別的, 這就是數據形式主體
箭頭表示方向,到底是往里面流還是往外抽
 
image_5b94b200_7e4f
中間形式
我們都知道,水管可不全都是一種規格的,就拿家里裝修常用的水管就有 4/6分管 兩種
如果有一個閥門或者水龍頭是6分管,而你接入桶里面的是4分管
怎么辦?
顯然,你會找一個轉接頭一類的東西,這就是下圖中的黃色,橙紅色,綠色代表的部分,他們就是不同的水管
通過轉接頭與另外一種規格的水管能夠連接起來,這就是中間形式
image_5b94b200_63b
抽水模型中的流
在這個例子中,流就是對於抽水這一過程的抽象描述.
一個水管里面的水的走向, 設定好了之后, 就是固定了的, 他要么往這頭, 要么往另一頭
而且,他肯定有一個源頭/目的,水管得水不能憑空來,水管也不能憑空抽取水
另外,水管顯然不僅僅只是能抽取水, 他還可以輸送別的液體,比如酒,水,飲料,醬油醋......
而且,如果有了各種不同規格的水管以及轉接頭,你的這個管道將會更加強大

所以說,容器 桶 接上了水管,就有能力提供水或者存儲水,他就是一個流
如果這個流在整合上各種不同規格的轉接頭和水管,能力將會大大提升

1.2程序語言中的流的主要概念

含義/源/方向/數據形式/中間形式
流的含義:
在程序設計中,流是對於數據流動傳輸的一種抽象描述
任何有能力產出數據的數據源,或者有能力接受數據的接收端對象都是一個流 (也就是上面例子中的一個容器接上水管)
流的源和目的:
數據可能從本地文件讀取,或者寫入,  也可能發送到網絡上,這就是源和目的
流的方向:
同水管里面的流水一樣,也是只有兩個方向,流進或者流出,也就是我們常說的輸入  和  輸出
流的數據形式:
數據的具體形式就是流傳送的內容,可能是字節,也能是字符,這就是數據的形式
流的中間形式:
對於任何一個流對它的功能進行一些必要的擴充,就好像接上了轉接頭的流可以接到其他規格的水管一樣
在一個流的基礎上 包裝,裝飾上其他的一些功能,流就會變得更加強大

1.3 流相關概念詳細解讀

 

1.3.1 流的源和目的

1.文件
最基本的一個數據源就是我們前文提到過的文件,文件不僅java中有,其他語言中也擁有文件的概念
2.字節數組
數據最基本的單位是字節
數組是在程序設計中,為了處理方便, 把具有相同類型的若干變量按有序的形式組織起來的一種形式
這些按序排列的同類數據元素的集合稱為數組
所以字節數組,自然是為了更方便操作字節的一種數據組織形式
3. 字符數組/String對象
既然數組可以簡化更方便的進行操作,而且也有字節數組
是不是還應該有字符數組呢?
而且,java中的String對象 ,它的內部實現也是char數組,java中使用char表示字符,這不就是字符數組么
4. 管道
"管道"的概念也是類似字面含義,一端輸入,就可以從一端流出,就好像一個水管一樣,
主要用來多線程之間直接進行數據交互,所以說數據來源也可能是一個管道
5.網絡等
其他數據源比如網絡等,java的強項就是WEB,從網絡接收數據是再自然不過的事情
6.流
另外流本身也可以作為一種源,所以一個流的源可以來自另外的一個流
 

1.3.2 流的方向

流的方向很簡單,只有兩個方向,輸入 或者 輸出
 

1.3.3 流的數據形式

計算機存儲數據是二進制的 0 1 序列
計算機中存儲容量的最小的單位是位(bit)最基本的單位是 字節 (byte)
字節是通過網絡傳輸信息(或在硬盤或內存中存儲信息)的單位
也就是說任何其他形式的數據,都可以而且,最終也都是用字節來表示
所以數據最基本的形式就是字節 
1  byte = 8 bit  
我們的世界充滿了各種符號
字符是表示數據和信息的字母、數字或其他符號
在電子計算機中,每一個字符與一個二進制編碼相對應,這是一個編碼的過程
所以說,數據的基本形式有  字節 和 字符兩種形式

1.3.4流的中間形式

放學回家的例子,我們很清楚的知道,火車和汽車是我們 人的中間形式過程,經過轉換(買票上車),  地上的人看不到我們了,看到的只是火車
對於流來說,中間形式是什么樣子的呢?
比如我們想要把一個Int類型直接寫入到文件中,怎么辦呢?
我們是不是需要把這個類型的數據處理下 轉換下呢  或者說包裝下 就如同你坐上了車(車把你裝了進去,形式就是車),總之就是要處理下
比如想要緩沖,按照行,按照字等等
這就是一種中間形式,后面我們會詳細介紹涉及到的中間形式
不過很顯然,中間形式並沒有向從某種數據源讀取數據那么剛需
但是他會給你提供更多的功能,讓你的流功能更加多變,擴展
如果有了中間形式,你可能就能夠直接把一個int寫入到文件上,這不是很方便么 

1.3.5流的種類-基本功能 擴展功能

想要完成一個IO類庫的基本功能,只需要把握住三點
1. 流的源和目的
2. 流的數據形式 
3. 流的方向  
想要做得更好就需要把握好流的中間形式,提供更強大的功能
 
 
流的源和目的 文件 / 字節數組 /管道 /字符數組/String對象 / 網絡 / 流
流的數據形式 字符  /  字節
流的方向 輸入  / 輸出
現在我們掌握了流的基本屬性,上表中的三種,也掌握了他們可能的變量值 
很簡單,只需要使用簡單的組合進行計算,我們就可以列舉出來所有可能的組合
下面我們試着列一些(並不會列出來全部內容)
文件(源) 輸入        字節              
文件(源) 輸入 字符
文件(目的地) 輸出 字節
文件(目的地) 輸出 字符
字節數組(源) 輸入 字節
字節數組(源) 輸入 字符
字節數組(目的地) 輸出 字節
字節數組(目的地) 輸出 字符
管道(源) 輸入 字節
管道(源) 輸入 字符
管道(目的地) 輸出 字節
管道(目的地) 輸出 字符
 
等等................等等................
還有很多種組合,   我相信你肯定可以排列的出來
不過很顯然,我們此處只是簡單的羅列,窮舉出所有組合的可能
對於類庫的設計自然不能這么簡單暴力,或許有些組合沒有必要,或許有些組合不符合邏輯
去掉那些無用的,不合邏輯的,無意義的,那么剩下來的組合形式,其實就是IO類庫要解決的問題
也就是就剩下了我們現在看得到的JavaIO類庫了 接下來從整體上對IO類庫進行介紹

2. JAVA  IO類庫體系結構

java.io
 
image_5b94b200_5fdd
 
java.io包中(JDK8),有87個類,其中有一些輔助類 還有一些異常類
去掉這些之后,剩下的絕大多數都是IO類體系的直接相關類,看起來很雜亂繁多
我們接下來講從整體上對涉及到的IO類進行介紹,等看完本篇文章,相信你應該能有一個整體的把控
只有從整體把控才有可能掌握整個完整的類家族

2.1 流的四大家族

如果先不考慮數據的來源,根據流的方向(輸入 和 輸出)以及流的數據形式(字符 和 字節) 我們有四種形式
輸入 字節
輸出 字節
輸入 字符
輸出 字符
 
 
四種形式 輸入字節  輸出字節  輸入字符   輸出字符
Java中名稱 InputStream OutPutStream Reader Writer
 
可以看得出來在命名上,類庫設計者的一些想法
把字節使用Stream作為后綴,或許因為字節是最基本的單位,所以他才是流Stream
我們平時閱讀  read和書寫write的都是字符,所以使用Reader 和 Writer表示字符的輸入和輸出也很自然
image_5b94b201_583f
 

節點流與過濾流

我們上面講述流的含義概念時,反復提到了流的基本功能以及中間形式
基本功能就是針對於不同數據源的操作,屬於剛需范圍
而中間形式則是剛需的強有力的增強
流的數據源/目的  流的方向  流的數據類型的組合,構成了基本功能的完整集合
而對於增強型的流的形式,則是Java IO出彩的地方,屬於增強型的功能
java中針對於基本數據源進行操作的流叫做 節點流
而對於那些起到增強裝飾功能的流,叫做 過濾流
 
按照我們上面的思維邏輯
只需要把相關的數據源與我們上面的這四種基本形式進行組合
就可以得到流的基本功能家族,也就是節點流
根據節點流需要的拓展功能,我們就可以推演出來過濾流
 
2.2  流體系類層次結構詳解
 

2.2.1  InputStream

 

2.2.1.1  InputStream節點流

 
數據源與InputStream的結合
字節數組 ByteArrayInputStream (java.io)
文件
FileInputStream (java.io)
管道
PipedInputStream (java.io)
String
StringBufferInputStream (java.io)  
對象 ObjectInputStream (java.io)
上面就是IO類庫提供給我們的基礎功能
也就是可用的有效的合理的數據源與InputStream的組合(InputStream  流的方向與流的數據形式的組合)
類名 功能 構造方法
ByteArrayInputStream 從字節數組中讀取數據,也就是從內存中讀取數據
包含一個內部緩沖區,指向該字節數組
內部計數器跟蹤 read 方法要提供的下一個字節
關閉 ByteArrayInputStream 無效
此類中的方法在關閉此流后仍可被調用,而不會產生任何 IOException
ByteArrayInputStream(byte buf[])
ByteArrayInputStream(byte buf[], int offset, int length)
不是復制而來,直接指向地址
多參數的帶偏移量
FileInputStream 用於從文件中讀取信息 FileInputStream(String name)
FileInputStream(File file)
FileInputStream(FileDescriptor fdObj)
使用文件路徑名  抽象路徑名File 或者文件描述符
PipedInputStream 產生用於寫入相關Pipe的OutputStream的數據
實現管道化的概念
管道輸入流應該連接到管道輸出流;
管道輸入流提供要寫入管道輸出流的所有數據字節

通常,數據由某個線程從 PipedInputStream 對象讀取
並由其他線程將其寫入到相應的 PipedOutputStream
不建議對這兩個對象嘗試使用單個線程,因為這樣可能死鎖線程
PipedInputStream(PipedOutputStream src)
PipedInputStream(PipedOutputStream src, int pipeSize)
PipedInputStream()
PipedInputStream(int pipeSize) 
StringBufferInputStream 棄用,如果條件允許可以考慮使用StringReader
ObjectInputStream
對以前使用 ObjectOutputStream 寫入的基本數據和對象進行反序列化
ObjectOutputStream 和 ObjectInputStream 分別與 FileOutputStream 和 FileInputStream 一起使用時
可以為應用程序提供對對象圖形的持久存儲
ObjectInputStream 用於恢復那些以前序列化的對象
其他用途包括使用套接字流在主機之間傳遞對象,或者用於編組和解組遠程通信系統中的實參和形參。
 
ObjectInputStream(InputStream in)
ObjectInputStream()
 
SequenceInputStream可以說既不是節點流也不是過濾流,硬要算的話,可以說是節點流 算是一個工具類一樣的存在
SequenceInputStream (java.io) 兩個或者多個InputStream對象轉換為單一的InputStream SequenceInputStream(InputStream s1, InputStream s2)
SequenceInputStream(Enumeration<? extends InputStream> e)
 
image_5b94b201_33ff

2.2.1.2  InputStream過濾流

介紹過了InputStream的節點流,我們看下,我們還希望InputStream能夠哪些擴展的功能,也就是上面提到過的 流的中間形式
我們之前就提到過,希望能夠有直接操作數據類型的流,通過這個流可以直接操作基本數據類型的讀寫,而不需要自己去處理字節或者字節數組等
也就是說我們希望能夠對基本數據類型進行支持
IO是操作系統的瓶頸,如果過於頻繁的直接對磁盤IO進行讀寫,勢必會增加CPU的空閑,性能降低,我們希望能夠有緩沖的功能
IDE開發工具的編輯器都有行號的標志,行號可以給我們提供很多的便捷性,所以希望能夠跟蹤展示行號
比如當我們用程序讀取一行代碼,識別其中的關鍵字
比如 int i = 0; 讀取到int時,我們不知道他是不是關鍵字,可能是一個int0的變量名
讀取到下一個的時候,發現是空格,我們才能確定,他就是一個關鍵字
但是下面的空格已經被讀取了,我們可能希望接下來的掃描能夠讀取到空格,可是流是順序的,被消費了就不存在了
所以希望能夠把讀取到的字節回退到原來的流中
於是就有了 
支持基本數據類型/緩存/行號/回退  這幾種擴展功能的想法
 
功能點和InputStream組合下可以得到如下四種擴展功能  
Data表示基本數據類型  Buffer 表示緩沖  LineNumber表示行號 PushBack表示回退
DataInputStream (java.io)
BufferedInputStream (java.io)
LineNumberInputStream (java.io)
PushbackInputStream (java.io)
 
image_5b94b201_2db9
 
到底怎么實現呢?
顯然我們可以直接通過實現InputStream來實現這幾個子類,用於表示這幾個功能
但是就又出現了一個問題,如果既想要 支持基本數據類型,又想具有緩沖的功能怎么辦? 如果還用繼承的想法會出現什么問題?
那就又回到了組合的問題上來了,4種功能就會出現4*3*2*1=24 中組合,類的個數直接爆炸了.....
 
回想下我們之前想到過的設計模式---> 裝飾器模式
就可以完美的解決這個問題,裝飾器模式是繼承的一種良好替代方式,能過有效的避免類的個數的爆炸問題
並且還能夠動態的增加或者減少功能
看下UML圖
image_5b94b201_78e7
 
通過UML圖可以看得到,我們還需要一個Decorator類,我們的具體的裝飾類個數不止一個,顯然不能省略這個Decorator抽象類
(不清楚裝飾器模式的沒辦法理解這種邏輯,請務必看明白裝飾器模式)
這個Decorator就是我們的FilterInputStream (java.io)  
看下類圖,黑色部分為裝飾器模式的角色
節點流表示上面說到的節點流
ByteArrayInputStream/FileInputStream/PipedInputStream/ObjectInputStream/StringBufferInputStream

FilterInputStream中包含一個InputStream屬性(是你還有你)
image_5b94b201_17ba
image_5b94b201_7ddb


下面我們看下InputStream下的類繼承體系
現在你是否已經可以大致的明白,這些類都是做什么的了呢?
image_5b94b201_789e

另外還有一些不在java.io包中的類
這些不是IO主體系內的東西,但是依賴於IO ,從事着跟IO相關的一些工作,所以也擴展自InputStream
后面將會單獨進行介紹,此處不展開討論
SocketInputStream (java.net)
CheckedInputStream (java.util.zip)
DeflaterInputStream (java.util.zip)
GZIPInputStream (java.util.zip)
InflaterInputStream (java.util.zip)
ZipInputStream (java.util.zip)
JarInputStream (java.util.jar)
image_5b94b201_6211
 
 

2.2.2 OutputStream

2.2.2.1  OutputStream節點流

 
數據源與OutputStream的結合
字節數組 ByteArrayOutputStream (java.io)
文件
FileOutputStream (java.io)
管道
PipedOutputStream (java.io)
對象 ObjectOutputStream (java.io)
 
仍舊是數據源與OutputStream的組合
ByteArrayOutputStream
其中的數據被寫入一個 byte 數組
緩沖區會隨着數據的不斷寫入而自動增長, 可使用 toByteArray() 和 toString() 獲取數據
 
關閉 ByteArrayOutputStream 無效
此類中的方法在關閉此流后仍可被調用,而不會產生任何 IOException
ByteArrayOutputStream()
ByteArrayOutputStream(int size)
無參會調用有參,設置默認值
FileOutputStream 信息寫入文件 FileOutputStream(String name)
FileOutputStream(String name, boolean append)
FileOutputStream(File file)
FileOutputStream(File file, boolean append)
FileOutputStream(FileDescriptor fdObj)
與FileInputStream幾乎一樣,不同的是第二個參數用於設置是否是append追加
PipedOutputStream 可以將管道輸出流連接到管道輸入流來創建通信管道
管道輸出流是管道的發送端
通常,數據由某個線程寫入 PipedOutputStream 對象
並由其他線程從連接的 PipedInputStream 讀取
不建議對這兩個對象嘗試使用單個線程,因為這樣可能會造成該線程死鎖
PipedOutputStream(PipedInputStream snk)
PipedOutputStream()
ObjectOutputStream ObjectOutputStream 將 Java 對象的基本數據類型和圖形寫入 OutputStream
可以使用 ObjectInputStream 讀取(重構)對象
通過在流中使用文件可以實現對象的持久存儲
如果流是網絡套接字流,則可以在另一台主機上或另一個進程中重構對象
ObjectOutputStream(OutputStream out)
ObjectOutputStream()
 
image_5b94b201_34f3
 

2.2.2.2  OutputStream過濾流

類似InputStream,OutputStream也需要有支撐基本數據類型的功能,以及緩沖的功能
另外,既然是輸出,還希望能夠輸出各種類型的數據,這樣子將會更加方便
也就是 
基本數據類型支持/緩沖/便捷輸出
DataOutputStream (java.io)
BufferedOutputStream (java.io)
PrintStream (java.io)
image_5b94b201_794b
 
同InputStream 一樣
擴展的功能,類庫設計者依然是使用裝飾器模式
FilterOutputStream (java.io)  是我們的Decorator
image_5b94b201_7535
 
完整的家譜
 
image_5b94b202_66d1
 
 
非IO包中的,但是卻跟IO相關的一些功能點,跟OutputStream相關的類
SocketOutputStream (java.net)
CheckedOutputStream (java.util.zip)
DeflaterOutputStream (java.util.zip)
GZIPOutputStream (java.util.zip)
InflaterOutputStream (java.util.zip)
JarOutputStream (java.util.jar)
ZipOutputStream (java.util.zip)
 
擴展的家譜
image_5b94b202_6163
 

2.2.3 Reader

2.2.3.1  Reader節點流

數據源與Reader的結合
字符數組 CharArrayReader (java.io)
String StringReader (java.io)
文件
FileReader (java.io)
管道
PipedReader (java.io)
 
 
CharArrayReader 實現一個可用作字符輸入流的字符緩沖區 CharArrayReader(char buf[])
CharArrayReader(char buf[], int offset, int length) 
StringReader 其源為一個字符串的字符流 StringReader(String s)
FileReader 用來讀取字符文件的便捷類 FileReader(String fileName)
FileReader(File file)
FileReader(FileDescriptor fd)
PipedReader 管道字符輸入流 PipedReader(PipedWriter src)
PipedReader(PipedWriter src, int pipeSize)
PipedReader()
PipedReader(int pipeSize) 
 
字節和字符作為數據的存儲單位,自然經常有轉換的需要
InputStreamReader 就是InputStream 轉換為Reader的類
InputStreamReader 轉換為Reader
InputStreamReader 是字節流通向字符流的橋梁
它使用指定的 charset 讀取字節並將其解碼為字符
它使用的字符集可以由名稱指定或顯式給定,或者可以接受平台默認的字符集
每次調用 InputStreamReader 中的一個 read() 方法都會導致從底層輸入流讀取一個或多個字節
為了達到最高效率,可要考慮在 BufferedReader 內包裝 InputStreamReader
InputStreamReader(InputStream in)
InputStreamReader(InputStream in, String charsetName)
InputStreamReader(InputStream in, Charset cs)
InputStreamReader(InputStream in, CharsetDecoder dec)
構造方法很清晰,接受一個InputStream 並且可以自定義字符編碼
 
對於類的轉換,設計模式中使用了適配器模式
通過構造方法接收InputStream,然后通過內部的StreamDecoder處理
StreamDecoder  和 StreamEncoder  是作為字符輸入和輸出轉換的關鍵類,后續有時間會介紹到
image_5b94b202_452d
image_5b94b202_1a39
 
屬於適配器模式中的對象適配器模式
Reader 是Target
InputStream   是 被適配者 Adaptee
InputStreamReader   是  Adapter 
 
需要注意的是,FileReader   與字節流中的FileInputStream 和 FileOutputStream 也是不一樣的
FileReader 繼承 InputStreamReader

2.2.3.2  Reader過濾流

字符流Reader也依然有裝飾器模式的應用
BufferedReader (java.io)
LineNumberReader (java.io)
PushbackReader (java.io)
 
image_5b94b202_6908
不過需要注意,Reader字符流的裝飾器模式應用跟字節流的有些差別
在字節流中,擴展功能都是通過FilterInputStream 或者 FilterOutputStream 
 
然而,在我們的Reader中
BufferedReader  和 FilterReader 各自是一個裝飾器模式
在BufferedReader中,可以理解為只有一個具體的裝飾器的簡化版本
省略了抽象類
直接繼承自Reader
BufferedReader  融合了Decoder 和 ConcreteDecoder兩者
 
image_5b94b202_6536
是你還有你 BufferedReader 是Reader 還有一個Reader
在FilterReader中就跟之前的字節流中的裝飾器模式的應用基本一致了
FilterReader 表示抽象的裝飾器部件  Decoder
PushbackReader 表示具體的裝飾器
image_5b94b202_7f8c
是你還有你  FilterReader 是 Reader 還有 Reader
 
Reader家族完整的族譜
image_5b94b202_69d9
 

2.2.4 Writer

數據源與writer的結合
字符數組 CharArrayWriter (java.io)
String StringWriter (java.io)
文件
FileWriter (java.io)
管道
PipedWriter (java.io)
 
 
CharArrayWriter
實現一個可用作 Writer 的字符緩沖區
緩沖區會隨向流中寫入數據而自動增長  可使用 toCharArray() 和 toString() 獲取數據。
在此類上調用 close() 無效
並且在關閉該流后可以調用此類中的各個方法,而不會產生任何 IOException
 
CharArrayWriter()
CharArrayWriter(int initialSize)
內部包含char buf[] size為大小
構造方法用來初始化緩沖區
StringWriter 將輸出收集到一個字符緩沖區 StringBuffer的字符流,可以用來構造字符串
關閉 StringWriter 無效
此類中的方法在關閉該流后仍可被調用,而不會產生任何 IOException
StringWriter()
StringWriter(int initialSize)
構造方法初始化緩沖區
FileWriter 用來寫入字符文件的便捷類
類似FileReader繼承自InputStreamReader
他繼承自OutputStreamWriter
FileWriter(String fileName)
FileWriter(String fileName, boolean append)
FileWriter(File file)
FileWriter(File file, boolean append)
FileWriter(FileDescriptor fd)
構造方法都是用來設置文件
PipedWriter 管道字符流 PipedWriter(PipedReader snk)
PipedWriter() 
 
轉換流
OutputStreamWriter 類似InputStreamReader 作為轉換器使用
OutputStreamWriter 是字符流通向字節流的橋梁
可使用指定的 charset 將要寫入流中的字符編碼成字節
使用的字符集可以由名稱指定或顯式給定,否則將接受平台默認的字符集
每次調用 write() 方法都會導致在給定字符(或字符集)上調用編碼轉換器
為了獲得最高效率,可考慮將 OutputStreamWriter 包裝到 BufferedWriter 中
例如:
Writer out = new BufferedWriter(new OutputStreamWriter(System.out));
 
OutputStreamWriter(OutputStream out, String charsetName)
OutputStreamWriter(OutputStream out)
OutputStreamWriter(OutputStream out, Charset cs)
OutputStreamWriter(OutputStream out, CharsetEncoder enc)
獲取OutputStream然后進行轉換,或者指定具體的字符編碼
 
FilterWriter 類似其他的Filter類,作為裝飾器模式的Decoder角色
以便具體的裝飾器角色可以使用

 
BufferedWriter   以及  PrintWriter類似Reader  不同於字節流的裝飾器模式應用
他們都自成一個模式的應用
他倆都單獨是Writer 也都包含一個Writer
image_5b94b202_d38
 
Writer下完整的家譜
image_5b94b202_11b8
 

2.3 IO類層次結構總結

 
前面已經對IO類的基本層次結構進行了一個邏輯上的概述
我們現在歸納概括下一些基本特點
 
IO的邏輯功能設計點 由 數據源,流的方向,流的數據形式三部分組合而成,這個組合構成了IO的基本功能
另外還有擴展功能,擴展功能以基礎功能作為依托,底層依賴基本功能
每種形式的基本功能和擴展功能構成了該形式的功能的集合
數據源形式比較多,但是對於流的數據形式以及流的方向是固定的
所以所有的類的基礎,都是基於  流的數據形式以及流的方向的組合
也就是 字節輸入 字節輸出   字符輸入  字符輸出
這四個形式是固定的
分別使用 InputStream  OutputStream  Reader  Writer來表示這四大家族
前面兩個表示字節  后面兩個表示字符
絕大多數的擴展都以 上面四個名詞作為后綴,表示是他的家族成員
基本功能對於字節涉及下面幾個關鍵詞  
ByteArray   File  Piped  Object
擴展功能對於字節涉及涉及下面幾個關鍵詞 
Data  Buffered  Pushback  LineNumber print
基本功能對於字符涉及涉及下面幾個關鍵詞 
CharArray  String File  Piped
擴展功能對於字符涉及涉及下面幾個關鍵詞  
Buffered    Print
雖然四大家族都由基本功能以及擴展功能組成
但是字符和字節的實現形式卻並不完全相同
字節流的擴展功能比較依賴裝飾器角色FilterInputStream  以及 FilterOutputStream
但是字符流的擴展功能不完全依賴FilterReader  以及  FilterWriter
數據源與四大家族的結合組合成了基本功能  也就是節點流
擴展功能點與四大家族的結合組成了擴展功能 也就是過濾流
另外還有幾個工具一樣的存在
SequenceInputStream   用於合並InputStream
InputStreamReader 以及OutputStreamWriter 用於轉換 使用了適配器模式
 
本文主要是從邏輯上介紹了IO家族,雖然實現上都略有差異
但是基本的命名習慣和功能點四個家族是非常類似的
只有理解了類庫的邏輯出發點,才能理解IO整個的類庫,而本文正是從邏輯上去解讀類庫的設計
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM