Java IO 之 InputStream源碼

1、InputStream

InputStream是一個抽象類,即表示全部字節輸入流實現類的基類。它的做用就是抽象地表示全部從不一樣數據源產生輸入的類,例如常見的FileInputStream、FilterInputStream等。那些數據源呢?好比:java

1) 字節數組(不表明String類,但能夠轉換)git

2) String對象github

3) 文件web

4) 一個其餘種類的流組成的序列化 (在分佈式系統中常見)數組

5) 管道(多線程環境中的數據源)緩存

等等多線程

兩者,注意它是屬於字節流部分,而不是字符流(java.io中Reader\Writer,下面會講到)。socket

FilterInputStream是爲各類InputStream實現類提供的「裝飾器模式」的基類。所以,能夠分爲原始的字節流和「裝飾」過的功能封裝字節流。分佈式

2、細解InputStream源碼的核心

源碼以下:測試

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/**
  * 全部字節輸入流實現類的基類
  */
public abstract class SInputStream {
 
     // 緩存區字節數組最大值
     private static final int MAX_SKIP_BUFFER_SIZE =  2048 ;
 
     // 從輸入流中讀取數據的下一個字節,以int返回
     public abstract int read()  throws IOException;
 
     // 從輸入流中讀取數據的必定數量字節,並存儲在緩存數組b
     public int read( byte b[])  throws IOException {
         return read(b,  0 , b.length);
     }
 
     // 從輸入流中讀取數據最多len個字節,並存儲在緩存數組b
     public int read( byte b[],  int off,  int len)  throws IOException {
         if (b ==  null ) {
             throw new NullPointerException();
         }  else if (off <  0 || len <  0 || len > b.length - off) {
             throw new IndexOutOfBoundsException();
         }  else if (len ==  0 ) {
             return 0 ;
         }
 
         int c = read();
         if (c == - 1 ) {
             return - 1 ;
         }
         b[off] = ( byte )c;
 
         int i =  1 ;
         try {
             for (; i < len ; i++) {
                 c = read();
                 if (c == - 1 ) {
                     break ;
                 }
                 b[off + i] = ( byte )c;
             }
         }  catch (IOException ee) {
         }
         return i;
     }
 
     // 跳過輸入流中數據的n個字節
     public long skip( long n)  throws IOException {
 
         long remaining = n;
         int nr;
 
         if (n <=  0 ) {
             return 0 ;
         }
 
         int size = ( int )Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
         byte [] skipBuffer =  new byte [size];
         while (remaining >  0 ) {
             nr = read(skipBuffer,  0 , ( int )Math.min(size, remaining));
             if (nr <  0 ) {
                 break ;
             }
             remaining -= nr;
         }
 
         return n - remaining;
     }
 
     // 返回下一個方法調用能不受阻塞地今後讀取(或者跳過)的估計字節數
     public int available()  throws IOException {
         return 0 ;
     }
 
     // 關閉此輸入流,並釋放與其關聯的全部資源
 
     public void close()  throws IOException {}
 
     // 在此輸出流中標記當前位置
     public synchronized void mark( int readlimit) {}
 
     // 將此流從新定位到最後一次對此輸入流調用 mark 方法時的位置。
     public synchronized void reset()  throws IOException {
         throw new IOException( "mark/reset not supported" );
     }
 
     // 測試此輸入流是否支持 mark 和 reset 方法
     public boolean markSupported() {
         return false ;
     }
 
}

其中,InputStream下面三個read方法纔是核心方法:

?

1
public abstract int read()

抽象方法,沒有具體實現。由於子類必須實現此方法的一個實現。這就是輸入流的關鍵方法。

兩者,可見下面兩個read()方法都調用了這個方法子類的實現來完成功能的。


?

1
public int read( byte b[])

該方法是表示從輸入流中讀取數據的必定數量字節,並存儲在緩存字節數組b。其效果等同於調用了下面方法的實現:

?

1
read(b,  0 , b.length)

若是b的長度爲 0,則不讀取任何字節並返回 0;不然,嘗試讀取至少 1 字節。若是由於流位於文件末尾而沒有可用的字節,則返回值 -1;不然,至少讀取一個字節並將其存儲在 b 中。

思考:這時候,怪不得不少時候, b != –1 或者 b != EOF


?

1
public int read( byte b[],  int off,  int len)


在輸入數據可用、檢測到流末尾或者拋出異常前,此方法一直阻塞。

該方法先進行校驗,而後校驗下個字節是否爲空。若是校驗經過後,
以下代碼:

?

1
2
3
4
5
6
7
8
9
10
11
int i =  1 ;
try {
     for (; i < len ; i++) {
         c = read();
         if (c == - 1 ) {
             break ;
         }
         b[off + i] = ( byte )c;
     }
}  catch (IOException ee) {
}

將讀取的第一個字節存儲在元素 b[off] 中,下一個存儲在 b[off+1] 中,依次類推。讀取的字節數最多等於 len。設 k 爲實際讀取的字節數;這些字節將存儲在 b[off]  b[off+k-1] 的元素中,不影響 b[off+k]  b[off+len-1] 的元素。




由於有上面兩個read的實現,因此這裏InputStream設計爲抽象類。 

相關文章
相關標籤/搜索