A FilterInputStream contains some other input stream, which it uses as its basic source of data, possibly transforming the data along the way or providing additional functionality.
Subclasses of FilterInputStream may further override some of these methods and may also provide additional methods and fields.
publicvoidunread(int b)throws IOException { ensureOpen(); // 初始状态下 pos 是 buf 的 长度,代表 buffer 目前的容量 // 随着 unread, pos 向右移动,直到 pos = 0 // 表示 buf 中已经写满的数据,所以 // push back buffer is full. if (pos == 0) { thrownew IOException("Push back buffer is full"); }
// 写入数据 buf[--pos] = (byte)b; }
publicvoidunread(byte[] b, int off, int len)throws IOException { ensureOpen(); // pos 表示 push back buffer 当前的容量, // len > pos 表示待写入的数据的长度,已经超过,buffer 可以接受的容量 // 所以,直接抛出异常,但是这个异常描述,准确:Push back buffer is full // 可能此时 pos = 3, 而 len = 5, 所以对于当前这个 unread 调用来说 // 是没法写入数据的,因为空间不够,但不是 buffer is full // 事实上,buffer 还可以容纳 3 个字节。所以这个异常描述并不准确 if (len > pos) { thrownew IOException("Push back buffer is full"); }
// 将整个 buffer 中的字节拷贝到新的 buffer 中。 byte nbuf[] = newbyte[nsz]; System.arraycopy(buffer, 0, nbuf, 0, pos); // 更新 buf 字段 if (!bufUpdater.compareAndSet(this, buffer, nbuf)) { // Can't replace buf if there was an async close. // Note: This would need to be changed if fill() // is ever made accessible to multiple threads. // But for now, the only way CAS can fail is via close. // assert buf == null; thrownew IOException("Stream closed"); } buffer = nbuf; // 新的buffer ,相当于原来buffer的后面增加的新的空间 // 所以 markpos 和 pos 都没有变化,所以不需要进行调整。 } // 将 reset zone 的字节个数 赋给 count count = pos; // 向 buffer fill 数据 int n = getInIfOpen().read(buffer, pos, buffer.length - pos); if (n > 0) // count = validate zone + reset zone // n 是 validate zone 的数据 // pos 是 reset zone 的数据。 count = n + pos; }
publicsynchronizedintread(byte b[], int off, int len) throws IOException { getBufIfOpen(); // Check for closed stream if ((off | len | (off + len) | (b.length - (off + len))) < 0) { thrownew IndexOutOfBoundsException(); } elseif (len == 0) { return0; }
// n 表示目前已经向 b 中读取到的字节的个数。 // 下面通过循环不断向 b 中读取数据 // 所以初始情况下 n = 0, 表示已经向 b 中读取了 0 个字节。 int n = 0; for (;;) { // 已经向 b 中读取了 n 个字节 // 所以将 b 的下次读取的 offset: 设置成 off + n // 读取的 length: 设置成 len - n // nread 表示 read1 实际读取的字节个数 int nread = read1(b, off + n, len - n);
// nread <= 0 表明,此次 read1 调用 // 没有读取到数据。 n==0, 表明是循环中的第一次 // 所以返回 nread 表示读取的字节个数, // 如果 n != 0, 则说明已经循环多次了, // n 就是 当前 b 中的字节个数。所以直接返回 n if (nread <= 0) return (n == 0) ? nread : n;
// 此时 nread > 0 , 表明 read1 向 b 中读取到了 // 有效的数据,所以将 读取到的字节个数添加到 n n += nread;
// n >= len 表明 已经向 b 中读取了至少 len 个字节了 所以应该返回了。 if (n >= len) return n;
// 此时应该是 n < len, 就是向 b 中还未读取到 len // 个字节,应该进行循环读取, // 但是在循环读取前先判断一下,底层的流中是否 // 还有数据可供读取,如果没有自然,就没有必要继续 // 循环读取了,所以直接返回. // if not closed but no bytes available, return InputStream input = in; if (input != null && input.available() <= 0) return n; } }
// read1 实现的原则是,至多直接向底层流直接读取数据一次, // 否则,总是,先从 buf 中读取,如果 buf 读完,则调用 fill // 将 buf 填充,然后再从 buf 中读取。 privateintread1(byte[] b, int off, int len)throws IOException { int avail = count - pos;
// buf 中没有可以直接读取的数据。 if (avail <= 0) { /* If the requested length is at least as large as the buffer, and if there is no mark/reset activity, do not bother to copy the bytes into the local buffer. In this way buffered streams will cascade harmlessly. */ if (len >= getBufIfOpen().length && markpos < 0) { // len >= getBufIfOpen().length 的情况下,如果直接调用 // fill 进行数据填充,很可能造成 buf 的扩容操作。 // 所以在 mark 无效的情况的下,可能直接从底层的 in 流中读取数据 // 而不是 调用 fill, 这样就避免了 fill 中的对 buf 的扩容 // 从而避免的空间浪费。还有一个作用就是,如果 mark 无效, // 则没有必要维护当前的buff了(因为 len > buf.length) // 所以直接将数据读取到 b 中,而不是读取到 buf 中,再从 buf 读取到 b 中 // 减少数组之间的拷贝,从而提升的读取的效率。 // 当然如果 mark 是有效的(markpos >= 0) // 为了维护 markpos,也就是保留 reset zone 的字节区的数据, // 则必须得调用 fill, 此时扩容也是有必要的。 return getInIfOpen().read(b, off, len); }
If the method mark has not been called since the stream was created, or the number of bytes read from the stream since mark was last called is larger than the argument to mark at that last call, then an IOException might be thrown.
If such an IOException is not thrown, then the stream is reset to a state such that all the bytes read since the most recent call to mark (or since the start of the file, if mark has not been called) will be resupplied to subsequent callers of the read method, followed by any bytes that otherwise would have been the next input data as of the time of the call to reset.
其中就提到,markSupported returns true 并且 mark 方法也被调用了:then an IOException might be thrown, 可能会抛出 IOException ,所以说对于 mark & reset 接口来说,并不是说 mark 的参数 readlimit 就一定决定 reset 方法在读取超过 readlimit 个字节被调用时会一定抛出异常。
Reads the next line of text from the input stream. It reads successive bytes, converting each byte separately into a character, until it encounters a line terminator or end of file; the characters read are then returned as a String. Note that because this method processes bytes, it does not support input of the full Unicode character set.