InputStream:字节输入流、是所有字节输入流的父类、本身个抽象类、为字节输入流提供一个标准、和基本的方法及简单的实现、子类可以根据自己的特点进行重写和扩
展。InputStream中有一个抽象方法read()、是字节输入流的核心、要求子类必须实现此方法、此方法也是字节输入流的核心方法、
int avaliable();查看当前流中可供读取的字节数。
void close();关闭当前流、释放所有与当前流有关的资源。
synchronized void mark(int readlimit);标记当前流的读取的位子。
boolean markSupport();查看当前流是否支持mark。
abstract int read();读取当前流中的下一个字节、并以整数形式返回、若读取到文件结尾则返回-1。
int read(byte[] b);将当前流中的字节读取到字节数组b中、返回实际读取的字节数
int read(byte[] b, int off, int len);将当前流中的len个字节读取到从下标off开始存放的字节数组b中。
synchronized reset();重置当前流的读取位置到最后一次调用mark方法标记的位置。
long skip(long n);跳过(抛弃)当前流中n个字节。返回实际抛弃的字节数。
/** * 所有字节输出流的父抽象类。提供字节输入流所共有的基本的读取方法。 */ public abstract class InputStream implements Closeable { // skipBuffer的大小 private static final int SKIP_BUFFER_SIZE = 2048;
// 内置字节缓存数组、用于构建skip方法中临时存放抛弃的字节。 private static byte[] skipBuffer; /** * 抽象的方法 用于读取输入流中的下一个字节、由其实现类去重写。这也是流的关键方法、下面几个方法都是直接或者间接调用read()方法来实现。 * @return 0 到 255 之间的整数。如果读到流的结尾则返回 -1 。 */ public abstract int read() throws IOException; /** * 从方法实现也可看出、他是不断调用read(byte[] b, 0, b.length)这个方法作为其方法体。 * @param 作为一个缓存字节数组来存放从流中读取的字节。 * @return 读取的字节总个数、如果读到结尾、则返回-1. */ public int read(byte b[]) throws IOException { return read(b, 0, b.length); } /** * 不断的调用read()方法来读取流中的字节、存放到 b 中。 * @param b 用来存放读取的字节的字节缓存数组、off 从b[off]开始放 、len 放len个 * @return 返回读取的字节的总个数。 */ 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; } /** * 返回跳过的字节数的个数。 * 这里根本就看不出这个方法到底有什么实际的用途、但是当看到后面的子类实现类的方法体就知道了。 * @param n 我们想从从输入流中跳过的字节数 * @return 实际跳过的字节数、因为有可能输入流中没有那么多有效字节被抛弃、此时则会跳过剩余所有字节、返回的字节数也就是跳之前剩余的字节数。 */ 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) { //记录此次实际读取的字节数、后面参数的意义在于防止出现IndexOutOfBoundsException异常。 nr = read(localSkipBuffer, 0, (int) Math.min(SKIP_BUFFER_SIZE, remaining)); //如果读到输入流结尾、则结束循环。 if (nr < 0) { break; } //修改记录还要抛弃的字节数的值 remaining -= nr; } //将n减去还剩多少需要被抛弃的值就是实际抛弃的值 return n - remaining; } /** * 返回输入流中可读取的有效的字节数、若子类提供此功能、则需要重新实现。 */ public int available() throws IOException { return 0; } /** * 关闭流、释放所有与此流有关的资源。 */ public void close() throws IOException {} /** * 在输入流中标记当前位置、与reset()结合使用、 * 若子类不提供此功能则调用此方法没有任何效果。 * 若子类提供此功能、则需重新实现。 */ public synchronized void mark(int readlimit) {} /** * 与mark(int readlimit)结合使用、将此流定位到最后一次mark的位置、即调用reset之后、程序继续重mark的位置读取字节流。 * 若子类不支持此方法、调用则会抛出异常、可事先调用下面的markSupported()来查看当前流是否支持此功能。 */ public synchronized void reset() throws IOException { throw new IOException("mark/reset not supported"); } /** * 查看当前流是否支持mark、默认是false、即如果实现类不重写此方法就意味着其不支持mark。 */ public boolean markSupported() { return false; } }
OutputStream:字节输出流、同InputStream意义相同、本身是一个抽象类、为所有字节输出流提供一个标准、和一些简单的方法及简单实现。其核心方法是一个抽象方法: write(byte b)要求子类必须实现此方法、不同功能的类对此方法的实现方式不
一样、一般情况下子类要重写其大多数方法、或者新增一些方法、用于满足更多的需要。
abstract void write(byte b);将一个字节写入到当前输出流管道中。 void write(byte[] b);将字节数组b中所有字节写入到当前输出流管道中。 void write(byte[] b, int off, int len);将字节数组b从下标off开始、len个字节写入当前输出流管道中 void flush();flush当前流、将当前流中的所有数据冲刷到目的地中。 void close();关闭当前流、释放与当前流有关的所有资源。
public abstract class OutputStream implements Closeable, Flushable { /** * 将一个8位的字节写入到当前字节输出流中。其子类必须重写、实现此方法。 */ public abstract void write(int b) throws IOException; /** * 将字节数组中b.length个字节写入到当前输出流中。此方法相当与write(byte[] b, 0, b.length);因为其内部就是调用下面的方法。 */ public void write(byte b[]) throws IOException { write(b, 0, b.length); } /** * 将一个字节数组中从下标off开始、len个字节写入到当前输出流中。不断调用write来实现的。 */ 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 {} }