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

Java中IO框架——InputStream源码解析

2018-02-21 22:13 671 查看
InputStream 是所有字节输入流的父类。

它实现了 Closeable 接口:

public interface Closeable extends AutoCloseable {
// 关闭此流并释放与此流关联的所有系统资源。如果已经关闭该流,则调用此方法无效。
public void close() throws IOException;
}


Closeable 是可以关闭的数据源或目标。调用 close 方法可释放对象保存的资源。

下面来看 InputStream 的源码:

属性

// 最大可跳过缓冲数组大小
private static final int MAX_SKIP_BUFFER_SIZE = 2048;


重要方法

read()

// 从输入流中读取数据的下一个字节,返回值的int其实是byte转化的int
// 如果返回值为-1,说明没有可读的字节了
public abstract int read() throws IOException;


read(byte b[])

// 从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中
public int read(byte b[]) throws IOException {
// 调用下边的方法,无偏移的读取b数组长度等同的字节数
return read(b, 0, b.length);
}


read(byte b[], int off, int len)

// 将输入流中读取最多len个字节,并将其存储在缓冲区数组b中
// 偏移量代表读取的字节从b数组哪个下标开始存入
public int read(byte b[], int off, int len) throws IOException {
if (b == null) {
// 如果字节数组b为空,抛出空指针异常
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
// 如果偏移量或者长度不合适,跑出范围异常
throw new IndexOutOfBoundsException();
} else if (len == 0) {
// 如果读取长度为0,直接返回0
return 0;
}
// 调用read()方法读取一个字节,读取的字节为c
int c = read();
if (c == -1) {
// 如果读取字节为-1,说明没有读取到字节,返回-1即可
return -1;
}
// 将读取到的字节,存入的数组b中偏移量off的下标位置中
b[off] = (byte)c;
// 上边已经读取了一个字节,i从1开始,下边要开始循环读取共(len-1)个字节
int i = 1;
try {
for (; i < len ; i++) {
// 读取下一个字节
c = read();
if (c == -1) {
// 读取到-1说明读不到字节了,返回-1跳出循环即可
break;
}
// 下一个字节存入数组b的(off+i)下标处
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
// 返回读取到的字节个数
return i;
}


skip(long n)

public long skip(long n) throws IOException {
// 定义剩余要跳过的字节数量为remaining等于n
long remaining = n;
// 定义下边每次循环读取的字节数量为nr
int nr;
// 要跳过的字节数n小于等于0,说明不需要跳过字节则直接返回0
if (n <= 0) {
return 0;
}
// 跳过的字节数size
// 情况1,要跳过的字节数量大于2048,那么size就取2048
// 情况2,要跳过的字节数量小于2048,那么size就取要跳过的字节数量
int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
// 根据上一步确定的跳过的字节数size来定义字节数组
byte[] skipBuffer = new byte[size];
// 如果剩余要跳过的字节数量大于0就继续循环
while (remaining > 0) {
// 从0开始,读取size和remaining间较小数的字节存入skipBuffer中,返回读取字节数量为nr
// 这个循环中remaining即剩余跳过字节数量是不断减小的,所以有两种情况:
// 情况1,对应上边的情况1,要跳过的字节数太大,大于2048
// 要跳过的字节数和剩余的字节数相比,如果剩余的还是太大,那么就读取size个数的字节
// 情况2,对应上边的情况2
// 要跳过的字节数大于等于剩余要跳过的字节数,那么就直接读取剩余跳过的字节即可
nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
// 如果返回的字节数nr小于0,说明没有读取到字节,跳出循环
if (nr < 0) {
break;
}
// 剩余的字节数量,等于要减去已经读取了的字节
// 如果是情况1,多次循环,每次都减去2048,直到剩余的小于2048了,剩下的一次读取即可
// 如果是情况2,一次循环的读取就OK了,remaining为0
remaining -= nr;
}
// 返回跳过的字节数
// 如果中途没有读取到输入流末尾,remaining为0,所以返回值为n,即要跳过的都跳过了
// 如果中途读取到了末尾,那么触发了break,此时remaining仍大于0,
//    即此时跳过的自然少于需要跳过的大小,则实际跳过的自然要小
return n - remaining;
}


available()

子类应该进行重写的类

// 返回可读的字节数
public int available() throws IOException {
return 0;
}


close()

// 关闭输入流(该类未进行实现)
public void close() throws IOException {}


mark(int readlimit)

// 标记该位置,以便使用reset()方法回滚回该位置
public synchronized void mark(int readlimit) {}


reset()

// 回滚回mark()标记的位置
public synchronized void reset() throws IOException {
throw new IOException("mark/reset not supported");
}


markSupported()

// 判断是否支持mark()、reset()方法
public boolean markSupported() {
return false;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: