版权声明:此文章为作者原创,转载需要经过作者同意! https://blog.csdn.net/JavaDad/article/details/81663408
InputStream:字节输入流的所有类的父类
OutputStream:字节输出流的所有类的父类
这里的输入和输出是针对内存说的,一般来说,向内存读入数据为输入,从内存读出为输出。
下边是对两个类的源码分析:
InputStream.java
package java.io;
/**
* 字节输入流的所有类的超类
* 1. Closeable:实现close方法,可以在try-with-resource中自动关闭资源
*/
public abstract class InputStream implements Closeable {
// 在skip方法中使用
private static final int MAX_SKIP_BUFFER_SIZE = 2048;
/**
* 1. 读取输入流数据的下一个字节,返回这个字节的int值,一个字节能表示的大小为0-255,
* 所以这个方法的(正确)返回值范围是0-255。
* 2. 如果该输入流到达末尾处,没有可用的字节来读取,那么返回-1。
* 3. 该方法会阻塞,直到 1)有输入数据可用 2)到达流的末尾 3)有异常抛出。
* 4. 子类必须实现该方法
*/
public abstract int read() throws IOException;
/**
* 1. 读取输入流中若干(不是一个了,效率提升)字节并且将它们存储在缓冲数组中,返回实际读到的字节数量。
* 2. 该方法同样会阻塞,直到 1)有输入数据可用 2)到达流的末尾 3)有异常抛出。
* 3. 如果缓冲数组的长度为0,那么返回0;否则至少读取一个字节。
* 如果读到流的末尾,返回读取的字节数。
* 4. 第一个读取的字节存储在b[0],下一个存储在b[1],依次类推。读取到的字节数量最多等于b数组的长度。假设
* k是实际读取到的字节数量,这些字节将被存储到b[0]-b[k-1]中,b[k]-b[b.length-1]的元素不受影响。这里
* 的不受影响是什么意思呢??
*/
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
/**
* 1. 从输入流中读取len个字节到字节数组中,尽可能的读取len个字节,但是可能少于len个字节。返回实际读取到的字节数。
* 如果len=0,那么没有数据可读,返回0。
* 2. 第一个读取的字节存储在b[off]中,依次类推。最多读len个字节。
*/
public int read(byte b[], int off, int len) throws IOException {
// 如果缓冲数组为null,则抛出 NullPointerException
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
// 1. 如果数组存储数据的开始位置小于0,IndexOutOfBoundsException
// 2. 如果设置的读取字节长度小于0,IndexOutOfBoundsException
// 3. 如果数组偏移后的剩余长度不足len,IndexOutOfBoundsException
throw new IndexOutOfBoundsException();
} else if (len == 0) {
// 如果len=0,返回0,什么也不做
return 0;
}
int c = read();
// 如果读到的字节为-1,说明到达流的末尾,返回-1
if (c == -1) {
return -1;
}
// 将读取的第一个字节存入b[off]
b[off] = (byte)c;
// i表示读取到的字节数
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 表示传入需要跳过的字节数
// 返回实际跳过的字节数
// 1. 当输入流的数据大于n时,且 n<MAX_SKIP_BUFFER_SIZE时,则一次就可跳过n
// 2. 当输入流的数据大于n时,且 n>MAX_SKIP_BUFFER_SIZE时,则一次只能读取MAX_SKIP_BUFFER_SIZE个,最后一次读取
// n%MAX_SKIP_BUFFER_SIZE个
// 3. 当输入流的数据小于n时,且 n<MAX_SKIP_BUFFER_SIZE时,则一次就可跳过整个输入流,不是n
// 还有其它场景,原理大致一样
public long skip(long n) throws IOException {
// 记录每循环一次读取,剩余需要跳过的字节数
long remaining = n;
// 记录每次循环跳过的字节数
int nr;
// n 需要大于0,否则没有意义
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;
}
// 返回实际跳过的字节数,其实nr才是统计每次跳过的字节数的变量,原理是 remianing(最终的) = remaining(其实就是n)-(nr1+nr2+nr3+...),
// 返回 n-remianing = nr1+nr2+nr3+...
return n - remaining;
}
public int available() throws IOException {
return 0;
}
public void close() throws IOException {}
/**
* mark和reset方法一起使用,mark表示标记某个reset恢复的位置
*/
public synchronized void mark(int readlimit) {}
public synchronized void reset() throws IOException {
throw new IOException("mark/reset not supported");
}
/*
* 是否支持mark和reset方法
*/
public boolean markSupported() {
return false;
}
}
OutputStream.java
package java.io;
/**
* 字节输出流的超类,接收字节并将其发送到某个接收器
* 实现两个重要的接口:
* 1. Closeable:实现close方法,可以在try-with-resource中自动关闭资源
* 2. Flushable:实现flush方法,可以操作底层刷新流
*/
public abstract class OutputStream implements Closeable, Flushable {
/*
* 子类必须实现的方法
*/
public abstract void write(int b) throws IOException;
public void write(byte b[]) throws IOException {
write(b, 0, b.length);
}
public void write(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
for (int i = 0 ; i < len ; i++) {
write(b[off + i]);
}
}
public void flush() throws IOException {
}
public void close() throws IOException {
}
}