JAVA-IO流體系
在IO中,具體構件角色是節點流,裝飾角色是過濾流。
1、繼承自InputStream/OutputStream
的流都是用於向程序中輸入/輸出數據,且數據的單位都是字節(byte=8bit)
,如圖,深色的爲節點流,淺色的爲過濾流。
2、繼承自Reader/Writer
的流都是用於向程序中輸入/輸出數據,且數據的單位都是字符(2byte=16bit)
,如圖,深色的爲節點流,淺色的爲過濾流。
從圖中可以看出,InputStream就是裝飾者模式中的超類(Component),ByteArrayInputStream,FileInputStream相當於被裝飾者(ConcreteComponent),這些類都提供了最基本的字節讀取功能。而另外一個和這兩個類是同一級的類FilterInputStream即是裝飾者(Decorator),BufferedInputStream,DataInputStream,PushbackInputStream…這些都是被裝飾者裝飾後形成的成品。
爲什麼可以說:裝飾模式可以在不創造更多子類的情況下,將對象的功能加以擴展
,能理解這一點就能很好的掌握裝飾者設計模式的精髓,如果在InputStream這裏擴展出FilterInputStream類下面的裝飾類,那麼針對FileInputStream和ByteArrayInputStream就都要去實現一次BufferedInputStream了,那麼可能就會衍生出BufferedFileInputStream和BufferedByteArrayInputStream這樣的類,如果按照這樣的擴展方式去添加功能,對於添加功能的子類來說簡直是一場噩夢,好在裝飾着模式很好的解決了這個問題,現在我們只需要在過濾流類這裏維護一個超類,不論傳入的是什麼具體的節點流,那麼都只要套一層裝飾,就能對功能方法進行加強。
如果想要對文件輸入流進行緩存加強可以這樣裝飾:
File file = new File ("hello.txt");
BufferedInputStream inBuffered=new BufferedInputStream (new FileInputStream(file));
如果想要對字節數組輸入流進行緩存加強可以這樣裝飾:
byte[] byts="Hello".getBytes();
BufferedInputStream bf=new BufferedInputStream(new ByteArrayInputStream(byts));
那麼節點流上的類就可以平行擴展,而裝飾者同樣可以按照功能進行另外一個維度的擴展,調用的時候就可以按需進行組合裝飾,這樣就可以減少了子類還將對象的功能進行擴展,不得不佩服前人在該設計模式上的智慧,理解了這裝飾着模式後,就應該對java中IO流的體系進行梳理:
節點流類型
- 對文件操作的字符流有
FileReader/FileWriter,
- 字節流有
FileInputStream/FileOutputStream。
過濾流類型
- 緩衝流:緩衝流要“套接”在相應的節點流之上,對讀寫的數據提供了緩衝的功能,提高了讀寫效率,同時增加了一些新的方法。
- 字節緩衝流有
BufferedInputStream / BufferedOutputStream
,字符緩衝流有BufferedReader / BufferedWriter
,字符緩衝流分別提供了讀取和寫入一行的方法ReadLine和NewLine方法。 - 對於輸出的緩衝流,寫出的數據,會先寫入到內存中,再使用flush方法將內存中的數據刷到硬盤。所以,在使用字符緩衝流的時候,一定要先flush,然後再close,避免數據丟失。
- 字節緩衝流有
- 轉換流:用於字節數據到字符數據之間的轉換。
- 字符流
InputStreamReader / OutputStreamWriter
。其中,InputStreamReader需要與InputStream“套接”,OutputStreamWriter需要與OutputStream“套接”。
- 字符流
- 數據流:提供了讀寫Java中的基本數據類型的功能。
DataInputStream和DataOutputStream
分別繼承自InputStream和OutputStream,需要“套接”在InputStream和OutputStream類型的節點流之上。
- 對象流:用於直接將對象寫入寫出。
- 流類有
ObjectInputStream和ObjectOutputStream
,本身這兩個方法沒什麼,但是其要寫出的對象有要求,該對象必須實現Serializable接口,來聲明其是可以序列化的。否則,不能用對象流讀寫。(api以及demo在文末)
- 流類有
重點梳理一下:Java中Inputstream/OutputStream與Reader/Writer的區別
- Reader/Writer和InputStream/OutputStream分別是I/O庫提供的兩套平行獨立的等級機構,
- InputStream、OutputStream是用來處理8位元的流,也就是用於讀寫ASCII字符和二進制數據;Reader、Writer是用來處理16位元的流,也就是用於讀寫Unicode編碼的字符。
- 在JAVA語言中,byte類型是8位的,char類型是16位的,所以在處理中文的時候需要用Reader和Writer。
- 兩種等級機構下,有一道橋樑InputStreamReader、OutputStreamWriter負責進行InputStream到Reader的適配和由OutputStream到Writer的適配。
- 在Java中,有不同類型的Reader/InputStream輸入流對應於不同的數據源:
- FileReader/FileInputStream 用於從文件輸入;
- CharArrayReader/ByteArrayInputStream 用於從程序中的字符數組輸入;
- StringReader/StringBufferInputStream 用於從程序中的字符串輸入;
- PipedReader/PipeInputStream 用於讀取從另一個線程中的 PipedWriter/PipeOutputStream 寫入管道的數據。
- 相應的也有不同類型的Writer/OutputStream輸出流對應於不同的數據源:FileWriter/FileOutputStream,CharArrayWriter/ByteArrayOutputStream,StringWriter,PipeWriter/PipedOutputStream。
IO流的應用選擇
確定選用流對象的步驟
- 確定原始數據的格式
- 確定是輸入還是輸出
- 是否需要轉換流
- 數據的來源(去向)
- 是否需要緩衝
- 是否需要格式化輸出
特殊需求
- 從Stream轉化爲Reader,Writer:InputStreamReader,OutputStreamWriter
- 對象輸入輸出流:ObjectInputStream,ObjectOutputStream
- 進程間通信:PipeInputStream,PipeOutputStream,PipeReader,PipeWriter
- 合併輸入:SequenceInputStream
- 更特殊的需要:PushbackInputStream, PushbackReader, LineNumberInputStream, LineNumberReader