您的位置:首页 > 编程语言 > Java开发

Java IO 之 InputStream源码

2015-09-28 00:00 465 查看

一、InputStream

InputStream是一个抽象类,即表示所有字节输入流实现类的基类。它的作用就是抽象地表示所有从不同数据源产生输入的类,例如常见的FileInputStream、FilterInputStream等。那些数据源呢?比如:

1)字节数组(不代表String类,但可以转换)
2)String对象
3)文件
4)一个其他种类的流组成的序列化(在分布式系统中常见)
5)管道(多线程环境中的数据源)
等等

二者,注意它是属于字节流部分,而不是字符流(java.io中Reader\Writer,下面会讲到)。
FilterInputStream是为各种InputStream实现类提供的“装饰器模式”的基类。因此,可以分为原始的字节流和“装饰”过的功能封装字节流。

二、细解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
(IOExceptionee){


}


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/resetnotsupported"
);


}


//测试此输入流是否支持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
(IOExceptionee){

}
将读取的第一个字节存储在元素b[off]中,下一个存储在b[off+1]中,依次类推。读取的字节数最多等于len。设k为实际读取的字节数;这些字节将存储在b[off]到b[off+k-1]的元素中,不影响b[off+k]到b[off+len-1]的元素。

因为有上面两个read的实现,所以这里InputStream设计为抽象类。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: