流分類回顧
本文是JavaIO告一段落的總結帖
希望對JavaIO做一個基礎性的總結(不涉及NIO)
從實現的角度進行簡單的介紹
下面的這兩個表格,之前出現過
數據源形式 | 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(行號) | 無 | LineNumberReader | 無 | |
Pushback(回退) | PushbackInputStream | 無 | PushbackReader | 無 |
Print(打印) | 無 | PrintStream | 無 | PrintWriter |
流分為輸入輸出流兩種形式
數據格式又分為字節和字符兩種形式
他們組合而來了四大家族
InputStream OutputStream Reader Writer
|
所有的四大家族的流有兩種合成擴展方式: 按照數據源形式擴展 按照裝飾功能點擴展 |
數據源形式擴展
現在我們換一個維度,從實現的角度,重新介紹下IO
數據源擴展的根本 |
從這種形式的數據中讀取數據 寫入數據到這種數據形式 |
我們上面列出來了ByteArray File Piped Object String CharArray 這幾種常用的數據源形式
結合我們上面的概念,我們看一下,實際的實現
字節數組 / 字符數組 /String
ByteArray 內存數據 |
|
CharArray 內存數據 |
|
String 內存數據 |
|
上面的這三種數據源形式,從上面看的話,邏輯非常清晰
讀--->從哪里讀?--->你給我一個數據源--->我以IO的操作習慣(InputStream/Reader) 讀給你 |
寫--->IO的操作習慣寫(OutputStream/Writer) --->寫到哪里?--->寫到我自己內部的存儲里
|
有人可能覺得寫到你自己內部存儲里面干嘛,有毛用?
內存數據,如果僅僅是存起來放到他自己肚子里面當然毛用沒有
但是,他們都提供了吐出來的功能了
給[字節數組 字符數組 String] 提供了一個統一的一致性的讀寫形式,操作非常方便,不是么
|
真實數據使用引用指向
內部存儲是內部的存儲區
管道
pipe 管道用於直連 然后進行數據的傳輸 主要用於多線程數據共享 In 輸入管道里面有一個存儲區 Out 輸出管道內有個In的引用 Connect之后,In指向了某個實際的 輸入流 然后Out通過引用操作In里面的存儲區 In自己的讀方法也是操作這個存儲區 ![]() |
Pipe |
|
所以一旦理解了,JavaIO管道的模型,管道就實在是太簡單了![]() |
只需要記住: 輸入In里面 有一個存儲緩沖區, 輸出有一個引用指向了In connect將他們連接起來,他們共同操作一個池子 輸出往里面寫,輸入從里面讀 管子的方向只能是 : 輸出 -----> 輸入 |
文件
文件相關的,都是實實在在的要通過操作系統了 所以也就必然需要使用本地方法 在Java中一個文件使用File來描述,File是抽象路徑名 可以表示文件 也可以表示目錄 File可以通過String路徑名構造 另外還有文件描述符可以表示指代文件 |
File 磁盤數據 |
|
根據上面的說法,FileReader 和 FileWriter必然要是一種轉換流
File
磁盤數據
|
|
關於FileReader 和FileWriter說了那么多
其實只有兩句話,就是字節流與字符流之間進行轉換
Reader reader = new InputStreamReader( new FileInputStream(.......));
Writer writer = new OutputStreamWriter( new FileOutputStream(.......));
|
Object
功能的裝飾擴展
既然是功能的裝飾擴展,我們之前已經說過很多次,都是裝飾器模式
也就是說了很多遍的
是你還有你,一切拜托你,中間增加點功能 |
這個你,就是需要被裝飾的抽象角色Component
就是這四大家族 InputStream OutputStream Reader Writer
給讀和寫裝飾增加新的功能,也就是最根本的讀和寫方法,將都是使用ConcreteComponent的
在基本的讀和寫方法之上,提供了新的功能
Data |
|
緩沖的概念都是內部有一個緩沖區
緩沖輸入 是通過底層的流往自己的緩沖區寫入數據, 應用程序從緩沖輸入的緩沖區中讀取,提高了read速度
緩沖輸出 是把數據寫入到自己的緩沖區中,后續再把數據通過底層的流一並寫入,從而提高了write的速度
因為讀寫都是從緩沖區中進行的了
Buffered |
|
LineNumberReader 內部使用了一個lineNumber = 0; 用來記錄行號 這個行號可以使用方法設置和獲取 getLineNumber setLineNumber 但是他不改變流的位置 |
PushBack
裝飾器模式 方法依賴於被裝飾的實體 ConcreteComponent
只是內部有一個緩沖區,可以存放被回退掉的字符
所有的讀取方法在進行讀取的時候,都會查看緩沖區的數據
PushbackInputStream |
繼承自FilterInputStream 得到一個InputStream 引用in 構造方法需要 InputStream 內部有緩沖區byte[] buf |
FilterReader | 繼承自FilterReader 得到一個Reader引用 in 構造方法需要一個Reader 內部有緩沖區char[] buf |
Print
提供了多種形式的打印,根本只是在真的寫入數據前,將數據參數進行一些處理
根本的寫操作 依賴被裝飾的節點流提供
在數據寫入之前進行必要的數據處理
PrintStream | 繼承自 FilterOutputStream得到一個OutputStream 引用 out 構造需要一個OutputStream |
PrintWriter | 內部有一個out 構造方法需要一個Writer |
所以你看,擴展的功能通過裝飾器模式,他們的行為都是類似的,那就是:
1. 最基本的讀寫依賴被裝飾的具體的節點流
2. 然后進行了功能的增強
總結
說到這個地方,我們又從實現的角度把常用的一些流進行了介紹
你會發現看起來那么多,實際上並沒有多少
四大家族,以及幾種數據源形式,以及幾個擴展功能點
只要找准了思路,理清楚了邏輯,就不難理解了
不知道到底是恍然大悟?還是?恍然如夢 ?