物質 一個地方 流向了 另外一個地方 |
主體 | 人 人從一個地方到了另外一個地方 |
源/目的 | 學校/家 |
方向 | 回家或者返校 圖中的兩個箭頭 |
中間形式 | 火車和汽車 |
含義/源/方向/數據形式/中間形式 |
流的含義:
在程序設計中,流是對於數據流動傳輸的一種抽象描述
任何有能力產出數據的數據源,或者有能力接受數據的接收端對象都是一個流 (也就是上面例子中的一個容器接上水管)
|
流的源和目的:
數據可能從本地文件讀取,或者寫入, 也可能發送到網絡上,這就是源和目的
|
流的方向:
同水管裏面的流水同樣,也是隻有兩個方向,流進或者流出,也就是咱們常說的輸入 和 輸出
|
流的數據形式: 數據的具體形式就是流傳送的內容,多是字節,也能是字符,這就是數據的形式 |
流的中間形式: 對於任何一個流對它的功能進行一些必要的擴充,就好像接上了轉接頭的流能夠接到其餘規格的水管同樣 在一個流的基礎上 包裝,裝飾上其餘的一些功能,流就會變得更增強大 |
1.文件
最基本的一個數據源就是咱們前文提到過的文件,文件不只java中有,其餘語言中也擁有文件的概念
|
2.字節數組
數據最基本的單位是字節
數組是在程序設計中,爲了處理方便, 把具備相同類型的若干變量按有序的形式組織起來的一種形式
這些按序排列的同類數據元素的集合稱爲數組
因此字節數組,天然是爲了更方便操做字節的一種數據組織形式
|
3. 字符數組/String對象
既然數組能夠簡化更方便的進行操做,並且也有字節數組
是否是還應該有字符數組呢?
並且,java中的String對象 ,它的內部實現也是char數組,java中使用char表示字符,這不就是字符數組麼
|
4. 管道
"管道"的概念也是相似字面含義,一端輸入,就能夠從一端流出,就好像一個水管同樣,
主要用來多線程之間直接進行數據交互,因此說數據來源也多是一個管道
|
5.網絡等
其餘數據源好比網絡等,java的強項就是WEB,從網絡接收數據是再天然不過的事情
|
6.流 另外流自己也能夠做爲一種源,因此一個流的源能夠來自另外的一個流 |
流的方向很簡單,只有兩個方向,輸入 或者 輸出
|
計算機存儲數據是二進制的 0 1 序列
計算機中存儲容量的最小的單位是位(bit)最基本的單位是
字節
(byte)
字節是經過網絡傳輸信息(或在硬盤或內存中存儲信息)的單位
也就是說任何其餘形式的數據,均可以並且,最終也都是用字節來表示
因此數據最基本的形式就是字節
1 byte = 8 bit
|
咱們的世界充滿了各類符號
字符是表示數據和信息的字母、數字或其餘符號
在電子計算機中,每個字符與一個二進制編碼相對應,這是一個編碼的過程
|
因此說,數據的基本形式有 字節 和 字符兩種形式 |
放學回家的例子,咱們很清楚的知道,火車和汽車是咱們 人的中間形式過程,通過轉換(買票上車), 地上的人看不到咱們了,看到的只是火車 對於流來講,中間形式是什麼樣子的呢? 好比咱們想要把一個Int類型直接寫入到文件中,怎麼辦呢? 咱們是否是須要把這個類型的數據處理下 轉換下呢 或者說包裝下 就如同你坐上了車(車把你裝了進去,形式就是車),總之就是要處理下 好比想要緩衝,按照行,按照字等等 這就是一種中間形式,後面咱們會詳細介紹涉及到的中間形式 |
不過很顯然,中間形式並無向從某種數據源讀取數據那麼剛需 可是他會給你提供更多的功能,讓你的流功能更加多變,擴展 若是有了中間形式,你可能就可以直接把一個int寫入到文件上,這不是很方便麼 |
想要完成一個IO類庫的基本功能,只須要把握住三點 |
1. 流的源和目的
2. 流的數據形式
3. 流的方向
|
想要作得更好就須要把握好流的中間形式,提供更強大的功能 |
流的源和目的 | 文件 / 字節數組 /管道 /字符數組/String對象 / 網絡 / 流 |
流的數據形式 | 字符 / 字節 |
流的方向 | 輸入 / 輸出 |
文件(源) | 輸入 | 字節 |
文件(源) | 輸入 | 字符 |
文件(目的地) | 輸出 | 字節 |
文件(目的地) | 輸出 | 字符 |
字節數組(源) | 輸入 | 字節 |
字節數組(源) | 輸入 | 字符 |
字節數組(目的地) | 輸出 | 字節 |
字節數組(目的地) | 輸出 | 字符 |
管道(源) | 輸入 | 字節 |
管道(源) | 輸入 | 字符 |
管道(目的地) | 輸出 | 字節 |
管道(目的地) | 輸出 | 字符 |
輸入 | 字節 |
輸出 | 字節 |
輸入 | 字符 |
輸出 | 字符 |
四種形式 | 輸入字節 | 輸出字節 | 輸入字符 | 輸出字符 |
Java中名稱 | InputStream | OutPutStream | Reader | Writer |
能夠看得出來在命名上,類庫設計者的一些想法
把字節使用Stream做爲後綴,或許由於字節是最基本的單位,因此他纔是流Stream
咱們平時閱讀 read和書寫write的都是字符,因此使用Reader 和 Writer表示字符的輸入和輸出也很天然
|
字節數組 | ByteArrayInputStream (java.io) |
文件 |
FileInputStream (java.io)
|
管道 |
PipedInputStream (java.io)
|
String |
|
對象 | ObjectInputStream (java.io) |
類名 | 功能 | 構造方法 |
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) |
棄用,若是條件容許能夠考慮使用StringReader | ||
ObjectInputStream |
對之前使用 ObjectOutputStream 寫入的基本數據和對象進行反序列化
ObjectOutputStream 和 ObjectInputStream 分別與 FileOutputStream 和 FileInputStream 一塊兒使用時
能夠爲應用程序提供對對象圖形的持久存儲
ObjectInputStream 用於恢復那些之前序列化的對象
其餘用途包括使用套接字流在主機之間傳遞對象,或者用於編組和解組遠程通訊系統中的實參和形參。
|
ObjectInputStream(InputStream in) ObjectInputStream() |
SequenceInputStream (java.io) | 兩個或者多個InputStream對象轉換爲單一的InputStream | SequenceInputStream(InputStream s1, InputStream s2) SequenceInputStream(Enumeration<? extends InputStream> e) |
咱們以前就提到過,但願可以有直接操做數據類型的流,經過這個流能夠直接操做基本數據類型的讀寫,而不須要本身去處理字節或者字節數組等
也就是說咱們但願可以對基本數據類型進行支持
|
IO是操做系統的瓶頸,若是過於頻繁的直接對磁盤IO進行讀寫,勢必會增長CPU的空閒,性能下降,咱們但願可以有緩衝的功能
|
IDE開發工具的編輯器都有行號的標誌,行號能夠給咱們提供不少的便捷性,因此但願可以跟蹤展現行號 |
好比當咱們用程序讀取一行代碼,識別其中的關鍵字 好比 int i = 0; 讀取到int時,咱們不知道他是否是關鍵字,多是一個int0的變量名 讀取到下一個的時候,發現是空格,咱們才能肯定,他就是一個關鍵字 可是下面的空格已經被讀取了,咱們可能但願接下來的掃描可以讀取到空格,但是流是順序的,被消費了就不存在了 因此但願可以把讀取到的字節回退到原來的流中 |
DataInputStream (java.io)
BufferedInputStream (java.io)
LineNumberInputStream (java.io)
PushbackInputStream (java.io)
|
看下類圖,黑色部分爲裝飾器模式的角色 節點流表示上面說到的節點流 ByteArrayInputStream/FileInputStream/PipedInputStream/ObjectInputStream/ FilterInputStream中包含一個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)
|
字節數組 | ByteArrayOutputStream (java.io) |
文件 |
FileOutputStream (java.io)
|
管道 |
PipedOutputStream (java.io)
|
對象 | ObjectOutputStream (java.io) |
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() |
基本數據類型支持/緩衝/便捷輸出 |
DataOutputStream (java.io)
BufferedOutputStream (java.io)
PrintStream (java.io)
|
非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)
|
字符數組 | 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 | 轉換爲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 而且能夠自定義字符編碼 |
屬於適配器模式中的對象適配器模式
Reader 是Target
InputStream 是 被適配者 Adaptee
InputStreamReader 是 Adapter
|
BufferedReader (java.io)
LineNumberReader (java.io)
PushbackReader (java.io)
|
字符數組 | 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角色 以便具體的裝飾器角色可使用 |
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 用於轉換 使用了適配器模式 |