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設計爲抽象類。