首先说说
public abstract int read() throws IOException
,这个read方法返回的是一个unsigned的byte,范围是0-255.而java中不存在unsigned的byte类型,所以要用int来存放。而用int存放的其实只是unsigned byte的模拟实现
比如:
int[] data = new int[10];
for (int i = 0; i < data.length; i++) {
data[i] = System.in.read();
}
而如果使用byte数组,比如
byte[] b = new byte[10];
for (int i = 0; i < b.length; i++) {
b[i] = (byte) System.in.read();
}
byte数组里存放的是有符号数,范围-128~127
如果要将有符号数转回无符号数,那么可以通过公式int i = (b >= 0) ? b : 256 + b;
也可以通过b&&0xff来实现,
这其实是一个int byte转换的问题,java中的int和byte都是有符号数,当byte扩展为int时,自动添加位,比如
转换前 11010110 (有符号数 -42)
(转换,牵涉到符号位的扩展。因为扩展前符号位是1,所以扩展后,高位都是1)
转换后 11111111 11111111 11111111 11010110 (- 42),所以不变。
而当int转换成byte时,会采取截断前24位留下末尾8位的策略。当int的数值范围在-127~128时,截断不会产生任何影响,所以转换出来的byte与原始值一样。
再来看
public int read (byte b[] , int i, int j)
public int read(byte abyte0[], int i, int j)
throws IOException
{
if(abyte0 == null)
throw new NullPointerException();
if(i < 0 || j < 0 || j > abyte0.length - i)
throw new IndexOutOfBoundsException();
if(j == 0)
return 0;
int k = read();
if(k == -1)
return -1;
abyte0[i] = (byte)k;
int i1 = 1;
do
{
try
{
if(i1 >= j)
break;
int l = read();
if(l == -1)
break;
abyte0[i + i1] = (byte)l;
i1++;
continue;
}
catch(IOException ioexception) { }
break;
} while(true);
return i1;
}
参数i代表的是byte b[]的偏移量,说明从第i个位置开始赋值,j代表的是读取的字节数。
这个方法会先尝试着read()读取一个byte,如果恰好读到末尾,则返回-1。若没有读到末尾,便开始循环调用read()方法进行读取,并记录下读取的字节数。
所以,当此方法返回-1时,说明已经读取到末尾了。
最后看
public long skip(long l)
public long skip(long l)
throws IOException
{
long l1 = l;
if(l <= 0L)
return 0L;
int j = (int)Math.min(2048L, l1);
byte abyte0[] = new byte[j];
do
{
if(l1 <= 0L)
break;
int i = read(abyte0, 0, (int)Math.min(j, l1));
if(i < 0)
break;
l1 -= i;
} while(true);
return l - l1;
}
该方法首先比较l和2048,选出较小的数作为byte b[]的长度。假设l大于2048,则j=2048,数组长度为2048,循环中每次都会读取2048个字节,并从l1中扣除读取到的2048个字节,现在考虑两种情况:1,不会读到末尾。那么某一时刻,l1会小于2048,那么只需再读取l1个字节就退出循环。2,会读取到末尾。此时,会先读取到末尾,然后在下一次的循环时i为-1,跳出循环。
skip方法返回实际跳过的字节数。