我们在学习Java IO流的时候,无论是字节流InputStream类还是字符流Reader类,read方法及其重载函数都是经常使用到的方法。
InputStream类的read及重载方法:
在“Java核心技术卷二 高级特性”一书中,是这样描述InputStream类的read方法的:abstract int read()
从数据中读入一个字节,并返回该字节。这个read方法在碰到输入流的结尾时返回-1。
我们都知道在Java中,字节以关键字byte表示,而byte类型的取值范围是:-128~127,其中便包含了-1这个值,这样一来计算机无法知道这个-1到底是文件的末尾还是数据中间的一个有效值。为了避免这个问题的发生,Java通过高位补0的方式将byte类型强制转换为int类型。这样描述难免有点抽象,我们先复习一些关于二进制的基础知识来理解这个流程:
一个字节是8位二进制组成的,例如:00000001代表着十进制的1,最高位为符号位。如果在无符号表示中,那么所有位数均为数值位;如果在有符号表示中,那么最高位为符号位,其他位为数值位。在Java中没有无符号这种说法,byte的取值范围是:-128至127。而InputStream底层由C/C++实现,返回一个无符号byte,取值范围为0~255。所以在Java中,将有符号的-1表示为无符号时,应取其-1补码(原码:10000001,除符号位以外数值位的反码+1):11111111,这个8位字长的二进制数在无符号位中为255,所以可以推导得出,在Java中的255则代表着数据中的-1这个数据,254代表着数据中-2......以此类推,我们只需要将得到的二进制数再次补码,即可获得原输入流的真实数据。so easy!
接下来的事情就好办了!在Java中,int类型占用4个字节,即32位,将byte类型强制转换为int类型只需要在高位24位补0即可,即:
00000000 00000000 00000000 11111111
我们成功的把byte类型转为了int类型,并且这是一个0~255取值范围的int类型!
所以如果我们获得了一个-1的int值,那么我们就可以确定这是一个输入流结尾而不是一个有效的数据。
Reader类read及重载方法:
在“Java核心技术卷二 高级特性”一书中,是这样描述Reader类的read方法的:abstract int read()
read() 方法将返回一个Unicode码元(一个在0~65535之间的整数),或者在碰到文件结尾时返回-1。
相比于InputStream类的read方法,Reader类方法就简单了许多。首先我们理解一下Unicode码元,它是一个由2个字节16位组成的字符,也就是说Reader类的read方法每次调用都会返回2个字节,而不是InputStream类的一个字节,并且这个返回是0至65535(2的16次方)的整数。非常让人感觉到安心的是Reader类的read方法返回值都是正整数不包含负数,并且它是int类型的取值范围内,将它强制类型转为int类型时,如果read方法读取到-1,则可以百分百确定这是由于输入流已经抵达末尾得到的值,并不是数据的中间有效值,更不存在数据截断。所以 Reader 下 read 方法返回的 char 类型数据直接转为了 int 类型。