你好!歡迎閱讀我的博文,你可以跳轉到我的個人博客網站,會有更好的排版效果和功能。
此外,本篇博文為本人Pushy原創,如需轉載請注明出處:https://pushy.site/posts/1519819757
本文寫在po主初學JAVA時,在學習inputStream摸不着頭腦,受Java IO-InputStream家族 -裝飾者模式一文啟發,所以在理清思路時寫下本文。因為初學,如有錯誤,望指正。
因為和輸入流與之對應的還有輸出流(即OutputStream),在此只針對輸入流InputStream討論。
1. 家族老大:
一說起家族中的老大,InputStream自然是當仁不讓,在java的輸入流操作的類中,衍生出的基本子類有,可以理解為這些都是InputStream它的孩子(子類):

InputStream作為所有輸入流中的超類,包含從輸入流讀取數據的基本方法,所有的具體類都包含了這些方法,例如read()方法,它將讀取一個字節並將其以int類型返回,當到達輸入流的結尾時,返回-1,因此我們常常這樣操作:
byte data;
while ((data = (byte) bis.read()) != -1) {
// 當沒有達到輸入流的結尾時,繼續讀取並打印轉換成char類型的字符:
System.out.print((char) data);
}
這段代碼不了解不要緊,現在我們開始正式介紹InputStream家族。
2. 家族孩子:
家族中的子類各司其職,老大FileInputStream處理文件流,老二ByteArrayInputStream處理字節數組流...
例如,我們來看下老大是怎么工作的:
import java.io.*;
import java.util.Date;
public class FileInputStreamTest {
public static void main(String[] args) throws Exception{
try {
// 創建FileInputStream對象:
FileInputStream fis = new FileInputStream("E:\\text.txt");
// 得到起始時間:
long start = System.currentTimeMillis( );
byte byteData;
while ((byteData = (byte) bis.read()) != -1) {
System.out.print((char) byteData);
}
// 得到讀取后的結束時間:
long end = System.currentTimeMillis( );
// 計算出讀取的時間:
long diff = end - start;
System.out.println("讀取的時間時間共:" + diff);
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
工作完成后,我們可以得到老大干完活的花費的時間為:1097,但是家族老大嫌這家伙干活太慢了。老大無奈,叫來了它的弟弟老二BufferedInputStream,俗話說啊,兄弟齊心,其利斷金。果不其然,兄弟倆一塊干活效率果然加快了不少:
在如下的代碼中我們可以看到,通過將FileInputStream放到BufferedInputStream中的構造方法中去創建BufferedInputStream對象,這樣FileInputStream也就具有了緩存的輸入流功能。
public class BufInputStream {
public static void main(String[] args) throws Exception{
try {
// 通過緩沖區數據向輸入流添加功能,維護一個內部緩沖區以存儲從底層輸入流讀取的字節:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\text.txt"));
long start = System.currentTimeMillis( );
byte byteData;
while ((byteData = (byte) fis.read()) != -1) {
System.out.print((char) byteData);
}
long end = System.currentTimeMillis( );
long diff = end - start;
System.out.println("讀取的時間時間共:" + diff);
bis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
現在我們來看下兄弟倆一塊工作花費的時間吧:281。嘿!果然快了不少!看來增加緩沖流的功能的效果的確十分明顯。
這下老二在家族的名聲增大了不少,許多的兄弟都找他搭檔干活了。
3. 總結:
通過上文的假設,我們可以明白了在io-InputStream的家族中,采用了裝飾者的設計模式,即不改變原類文件和使用繼承的前提下,動態地擴展一個對象的功能(比如說這里的支持緩沖流),通過創建一個包裝對象(這里的BufferedInputStream),也就是裝飾包裹真實的對象。

例如我們還可以也ByteArrayInputStream中修飾PushbackInputStream類:
PushbackInputStream pbi = new PushbackInputStream (new ByteArrayInputStream(b));
ByteArrayInputStream是處理字節數組流;PushbackInputStream是向輸入流中添加功能,允許使用unread()方法推回讀取的字節。這樣我們就可以使用pbi對象處理字節數組,還具有推回讀取字節的功能了:
import java.io.*;
public class BAStreamAndPBStream {
public static void main(String[] args) throws IOException{
byte[] b = {1,2,3};
PushbackInputStream pbi = new PushbackInputStream (new ByteArrayInputStream(b));
int result;
while ((result = pbi.read()) != -1) {
System.out.print(result + " ");
pbi.unread(result);
pbi.read();
System.out.print(result + " ");
}
pbi.close();
}
}
// 運行結果為:
// 1 1 2 2 3 3
好了,有關InputStream的大家族到這里介紹完了!如果你還有不明白的,可以閱讀一下文章Java IO-InputStream家族 -裝飾者模式。
