InputStream 源码分析

InputStream是所有输入字节流类的超类。所有InputStream的子类必须提供返回下个字节的方法。


public abstract class InputStream implements Closeable {

private static final int SKIP_BUFFER_SIZE = 2048;

private static byte[] skipBuffer;

// 从输入流中读取下个字节的数据,返回的字节是以int类型表示的(0~255)。如果已经到了流的末尾,返回-1。这个方法会被阻断直到输入流可用,已经到了末尾,或者抛出异常。
public abstract int read() throws IOException;

// 从流中读取b长度的字节到b中。
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}

// 从流中读取最多len长度的字节并存储到b中,返回实际读取的字节数。
// 这个方法会被阻断直到输入流可用,已经到了末尾,或者抛出异常。
// 如果数组长度为0,那么不会读取字节,返回0;否则试着去读取至少一个字节,如果到了流的末尾,返回-1。
// 第一个读取的字节会被保存到b[0]中,下一个会被保存到b[1]中。读取的字节数最大值是b的长度。b中剩余的部分不受影响。
// 该方法重复调用read()。如果第一次调用报IOException异常,该异常会被抛到该方法。如果接下来对read()的调用报IOException异常,异常会被获取并当成是文件的结尾。前面读取的字节会被保存到b中,返回读取的字节数。该方法的默认实现会阻断直到已经读取len长度字节的数据,检测到文件末尾,或者有异常抛出。子类可以提供更高效的实现。
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 个字节的数据。
//出于各种原因,skip 方法最终跳过的字节数可能更少一些,甚至可能为0。这可能是一些因素导致的,在跳过n个字节之前已经到达文件末尾只是其中一种可能。返回实际跳过的字节数。如果n为负值,不跳过任何字节。
// 该方法创建一个字节数组并不断地读取数据放到里面直至读取到n个字节或者到达流末尾。子类可以提供更高效的方法实现。
public long skip(long n) throws IOException {

long remaining = n;
int nr;
if (skipBuffer == null)
skipBuffer = new byte[SKIP_BUFFER_SIZE];

byte[] localSkipBuffer = skipBuffer;

if (n <= 0) {
return 0;
}

while (remaining > 0) {
nr = read(localSkipBuffer, 0,
(int) Math.min(SKIP_BUFFER_SIZE, remaining));
if (nr < 0) {
break;
}
remaining -= nr;
}

return n - remaining;
}

// 返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。
// 某些子类会返回流的所有字节数,有些不会。根据这个返回值来分配一个缓冲区来存取流中的所有数据是不对的。
// 子类需要重写该方法。
public int available() throws IOException {
return 0;
}

// 关闭流并且释放所有和这个流关联的系统资源
public void close() throws IOException {}

// 在流中标记当前位置。以后再调用reset时就可以再回到这个mark过的地方,这样再次读取到同样的字节。
// readlimit参数告诉系统,在读出这么多个字符之前,这个mark保持有效。
// mark通常的规范是:如果markSupported返回true,在调用mark方法后,流以某种方式记录所有读取的字节,当调用reset方法后,能够再次提供同样的字节。但是,在调用reset之前,流不必记录readlimit以外的字节。
// 在已经关闭的流上调用mark方法对流没有影响
public synchronized void mark(int readlimit) {}

// 将该输入流重新定位到上一次调用mark方法时标记的位置
// 如果markSupported返回true:
// 如果从流创建后,mark还未被调用过,或者调用mark后,读取的字节数大于mark的参数readlimit,可能会抛出IOException异常。
// 如果异常没有抛出,上次调用mark方法读取的所有字节(从文件的起始位置,如果mark方法没有调用)能够再次提供给以后的read方法,后跟任何从调用 reset 时起将作为下一输入数据的字节。
// 如果markSupported返回false:
// 对 reset 的调用可能抛出 IOException
// 如果未抛出 IOException,则将该流重新设置为一种固定状态,该状态取决于输入流的特定类型及其创建方式。提供给 read 方法后续调用者的字节取决于特定类型的输入流。
public synchronized void reset() throws IOException {
throw new IOException("mark/reset not supported");
}

// 查看输入流是否支持mark和reset方法。对于某个特定的流实例来说,是否支持mark和reset方法是不变的属性。
public boolean markSupported() {
return false;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值