如果你開啟過java.io,我想你肯定也被嚇到過,居然關於I/O有如此多的API,但是請不要害怕,今天我將從設計模式的角度帶你分析java的I/O。
什麼是I/O
input/output,通常指資料在內部儲存器和外部儲存器或其他周邊裝置之間的輸入和輸出。
而如今I/O問題是整個人機互動的核心問題,因為I/O是機器獲取和交換資訊的主要渠道。
然而I/O可以分為資料格式和傳輸方式,而這兩類正是影響效率的關鍵因素。 :pear:
資料格式分為:
- 位元組:InputStream 和 OutputStream
- 字元:Writer 和 Reader
傳輸方式分為:
- 磁碟操作:File
- 網路操作:Socket
位元組與字元之間的轉換
計算機的所有I/O操作都是基於位元組的,但是為什麼會有字元操作呢,這是因為我們在程式中操作的資料一般都是字元形式,所以為了操作方便,便提供了直接讀寫字元的Writer和Reader。
下面我將從介面卡模式的角度來分析位元組與字元。 :lollipop:
從原始碼角度分析
//繼承Reader,實現Reader的介面
public class InputStreamReader extends Reader {
//用於編解碼的物件
private final StreamDecoder sd;
public InputStreamReader(InputStream in) {
super(in);
try {
sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
} catch (UnsupportedEncodingException e) {
// The default encoding should always be available
throw new Error(e);
}
}
public int read() throws IOException {
return sd.read();
}
}
複製程式碼
每一個InputStreamReader繼承了Reader,然後通過StreamDecoder間接擁有了InputStream例項,因為byte到char需要編解碼。
所以InputStreamReader就是位元組和字元之間的介面卡,OutputStreamReader也是類似的實現。
FilterInputStream
接下來我將從FilterInputStream這個角色出發,來分析整個java.io包的架構。
由上圖分析,在裝飾者模式中,InputStream就是需要被裝飾的基類,FilterInputStream就是所有裝飾者的基類。 :cake:
java.io
現在我們就可以大致將java.io
包分為以下的情況。 :watermelon:
-
一些基礎介面。
例如:Closeable、Readable、DataInput。
-
Reader/Writer的所有子類,這些都是字元讀寫的介面卡,以及介面卡的擴充套件。
例如:InputStreamReader、FileReader、BufferedReader、CharArrayReader。
-
InputStream/OutputStream的所有子類,這些都是位元組讀寫的各種例項,是被裝飾的物件。
例如:FileInputStream、SocketInputStream、StringBufferInputStream、ByteArrayInputStream。
-
FilterInputStream/FilterOutputStream的所有子類,這些都是裝飾者,可以重複包裝。
例如:PushbackInputStream、BufferedInputStream、DataInputStream、LineNumberInputStream。
當然,上述的這些情況並不能完全描述java.io
包下的所有類,但是能夠使我們不再畏懼,對其有一個普遍巨集觀的認識,方便我們根據我們的需求對特定的物件進行深入分析。