IO家族類層次體系結構橫向匹配
上一篇文章中主要介紹了JavaIO流家族的整體設計思路,簡單回顧下
基本邏輯涉及數據源 流的方向,以及流的數據形式這三個部分的組合
按照流的數據形式和流的方向,組合而來了四大家族,分別是:
InputStream/OutputStream Reader/Writer
數據源與四大家族的組合構成了IO流的基本功能
數據源形式 | InputStream | OutputStream | Reader | Writer |
ByteArray(字節數組) | ByteArrayInputStream | ByteArrayOutputStream | 無 | 無 |
File(文件) | FileInputStream | FileOutputStream | FileReader | FileWriter |
Piped(管道) | PipedInputStream | PipedOutputStream | PipedReader | PipedWriter |
Object(對象) | ObjectInputStream | ObjectOutputStream | 無 | 無 |
String | StringBufferInputStream | 無 | StringReader | StringWriter |
CharArray(字符數組) | 無 | 無 | CharArrayReader | CharArrayWriter |
擴展功能基本通過裝飾器模式實現
擴展功能點 | InputStream | OutputStream | Reader | Writer |
Data(基本類型) | DataInputStream | DataOutputStream | 無 | 無 |
Buffered(緩沖) | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
LineNumber(行號) | LineNumberInputStream | 無 | LineNumberReader | 無 |
Pushback(回退) | PushbackInputStream | 無 | PushbackReader | 無 |
Print(打印) | 無 | PrintStream | 無 | PrintWriter |
從上面的列表應該可以看得出來,對於IO體系中的主要的一些類和接口
我們只需要明確兩點,就能夠更加深入的了解他們
1.針對於各種數據源,四大家族的處理邏輯
|
2.擴展功能點的含義 |
注意:
很多IO的成員並不操作磁盤上的文件
比如ByteArrayInputStream和ByteArrayOutputStream 接下來我們還會詳細的介紹到
他們並不直接操作持久化的數據(存儲在磁盤上的),還有不少其他的也都不是的
他們跟IO有什么關系?為什么他們要實現流的接口?
此處我想要提醒的是,
對於我們程序設計語言來說,IO 表示的是對數據的操縱,數據有讀寫
IO代表的是一類可讀可寫行為類似的事物,而不是指從磁盤上讀取文件
為什么不是有一個單純的類去進行對於字節數組的操作呢,為什么非要跟IO掛鈎沾邊?
首先,這並不是不可以,
的確是可以構造一個跟IO體系結構沒關系的字節數組
來操縱類進行字節數組的讀寫
可是,他的行為顯然跟IO非常的類似,在定義一套不同的接口顯然增加開發者使用成本
再者,不管從哪里讀 ,本身也仍舊是輸入輸出的問題
而且,針對不同的數據源提供一致性的接口,這也非常的符合面向接口的編程規范
所以,一句話,不要把IO狹隘地理解為操作磁盤上的文件.數據.
IO是輸入與輸出,是讀與寫的代名詞
IO數據源應用
ByteArray(字節數組)
字節數組,毫無疑問,不會應用在字符家族里面
他應用於 ByteArrayInputStream 以及 ByteArrayOutputStream
他的內部包含一個 字節數組 byte buf[]
ByteArrayInputStream 以及 ByteArrayOutputStream 內部維護了一個byte buf[]
會將數據讀取到這個字節數組(緩沖區)
或者將數據寫入到這個字節數組(緩沖區)
他們維護的是這個內部的字節數組本身,並不會寫入文件
|
這兩個類本質就是操縱字節數組,提供對字節數組的讀取與寫入 它的本質如同文件一樣,都是用來存儲數據 只不過是數據存在於內存中而已 通過將數據封裝到內部的字符數組中,可以提供IO一致性的接口 |
ByteArray 僅僅應用與字節流 |
File(文件)
前面說過,File 是最常見的一種數據形式 所以對IO提供針對文件的操作非常合理 我們知道,所有的數據存儲最終都是字節的形式 但是對於文件的操作又是如此的頻繁和重要 所以,針對於字符的輸入輸出也提供了對應的處理 不過還是那句話,最終文件都是字節形式存儲,所以,對於字符文件,自然需要進行編碼與解碼 FilterReader每一次的讀取都意味着一次解碼 FilterWriter每一次的寫入都意味着編碼 |
既然是文件,我們前面介紹過File類 File類的構造主要由路徑名或者文件描述符 所以對於文件的輸入輸出相關的IO操作,自然可以通過 路徑名 文件描述符 或者File 本身作為目標對象 也就是說構造函數的參數一般都是這三者之一 |
對於文件的操作是實實在在的操作文件本身 File 四大家族都有應用 |
Piped(管道)
管道的概念,不是來自於java io很早前就有此概念 含義非常明朗,就如同他的名字一樣,管道,好像兩個水管連接起來,形成一個通道 這個通道是直接連接的,並不會再跑到別的地方去彎彎繞 管道流的主要作用是可以進行兩個線程間的通訊 既然主要作用進行線程間的通訊,他就是傳輸數據使用的 IN 字節數組緩存數據,OUT使用IN對象 ![]() |
管道在四大家族中都有應用 |
Object
ObjectInputStream 和 ObjectOutputStream 的作用是,對基本數據和對象進行序列化操作支持
ObjectOutputStream對象能提供對“基本數據或對象”的持久存儲
ObjectInputStream,讀取出這些“基本數據或對象”
只有支持 java.io.Serializable 或 java.io.Externalizable 接口的對象才能被ObjectInputStream/ObjectOutputStream所操作
|
序列化自然不可能就只有字符,所以Object僅僅針對字節家族 |
String
提供了對String類型的支持 reader讀取到String writer寫入到StringBuffer |
![]() |
StringBufferInputStream 已經不推薦使用了 所以,后續可以認為String僅僅支持字符家族 |
CharArray
其實可以看得出來,只有File才是真正跟磁盤文件相關的
其他的數據源形式都是操作內存數據
IO擴展功能應用
Data(基本類型)
Data是對基本數據類型的支持 針對於DataOutputStream寫出的數據文件 可以使用DataInputStream進行讀取 也就是說是一種特殊形式的文件 |
他們底層依賴的還是字節流 通過繼承FilterInputStream 和 FilterOutputStream 使用其中的InputStream in 以及 OutputStream out 這兩個對象是通過構造方法傳遞進來的 |
Buffered(緩沖)
緩沖也就是為了減少讀取的頻率,設置一個緩沖區 緩沖的概念到處都是,所以緩沖應用於四大家族 |
LineNumber(行號)
LineNumber是針對輸入的 所以存在於LineNumberInputStream和LineNumberReader 不過對於字節流的LineNumberInputStream 已經棄用 |
LineNumberReader是一個跟蹤行號的緩沖字符輸入流 也很顯然,流都是順序讀取不能回退的,所以想要讀取行號自然要借助於緩存 他的實現繼承BufferedReader 也很好理解 |
Pushback
Print(打印)
主要是為了提供數據打印的便利性 |
打印自然是針對於輸出的 PrintStream PrintWriter |
本文從數據源以及擴展功能點的角度,再次分析了IO類庫的整體設計
雖然上一篇文章中對於所有的基本功能點以及擴展功能點已經做了一個介紹
本文再次提及是為了着重強調,數據源與擴展功能點在類層次結構中涉及的重要性
只有徹底明確了數據源以及擴展功能點的邏輯
才能徹底理解整個IO類庫架構設計