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;
	}

你可能感兴趣的:(java,Inputstream,buffer,closeable,skipbuffer)