• 输出流需要关闭,因此需要Closeable接口
  • 缓冲流需要刷新,因此需要Flushable接口

输入流的架构

image.png

输出流的基类

UML概述

image.png

重要方法

输入流将具体如何读,如何关闭留给了子类

read

从输入流中读取下一个字节的数据。值字节以 0 到 255 范围内的 int 形式返回(即int只有低八位有效,和写操作相对应)。如果由于已到达流的末尾而没有可用字节,则返回值 -1。此方法会阻塞,直到输入数据可用、检测到流结束或抛出异常为止。子类必须提供此方法的实现。

  1. /**
  2. * Reads the next byte of data from the input stream. The value byte is
  3. * returned as an <code>int</code> in the range <code>0</code> to
  4. * <code>255</code>. If no byte is available because the end of the stream
  5. * has been reached, the value <code>-1</code> is returned. This method
  6. * blocks until input data is available, the end of the stream is detected,
  7. * or an exception is thrown.
  8. *
  9. * <p> A subclass must provide an implementation of this method.
  10. *
  11. * @return the next byte of data, or <code>-1</code> if the end of the
  12. * stream is reached.
  13. * @exception IOException if an I/O error occurs.
  14. */
  15. public abstract int read() throws IOException;

将输入流中最多 len 个数据字节读入 byte 数组。尝试读取 len 个字节,但读取的字节也可能小于该值。以整数形式返回实际读取的字节数。在输入数据可用、检测到流末尾或者抛出异常前,此方法一直阻塞。如果 len 为 0,则不读取任何字节并返回 0;否则,尝试读取至少一个字节。如果因为流位于文件末尾而没有可用的字节,则返回值 -1;否则,至少读取一个字节并将其存储在 b 中

将读取的第一个字节存储在元素 b[off] 中,下一个存储在 b[off+1] 中,依次类推。读取的字节数最多等于 len。设 k 为实际读取的字节数;这些字节将存储在 b[off] 到 b[off+k-1] 的元素中,不影响 b[off+k] 到 b[off+len-1] 的元素。在任何情况下,b[0] 到 b[off] 的元素以及 b[off+len] 到 b[b.length-1] 的元素都不会受到影响。

类 InputStream 的 read(b, off, len) 方法重复调用方法 read()。如果第一次这样的调用导致 IOException,则从对 read(b, off, len) 方法的调用中返回该异常。如果对 read() 的任何后续调用导致 IOException,则捕获该异常并将其视为到达文件末尾;到达该点时读取的字节存储在 b 中,并返回发生异常之前读取的字节数。千言万语一句话,就是中途抛异常不影响已经读到的数据。

在已读取输入数据 len 的请求数量、检测到文件结束标记、抛出异常前,此方法的默认实现将一直阻塞。建议子类提供此方法更为有效的实现。

  1. /**
  2. * Reads up to <code>len</code> bytes of data from the input stream into
  3. * an array of bytes. An attempt is made to read as many as
  4. * <code>len</code> bytes, but a smaller number may be read.
  5. * The number of bytes actually read is returned as an integer.
  6. *
  7. * <p> This method blocks until input data is available, end of file is
  8. * detected, or an exception is thrown.
  9. *
  10. * <p> If <code>len</code> is zero, then no bytes are read and
  11. * <code>0</code> is returned; otherwise, there is an attempt to read at
  12. * least one byte. If no byte is available because the stream is at end of
  13. * file, the value <code>-1</code> is returned; otherwise, at least one
  14. * byte is read and stored into <code>b</code>.
  15. *
  16. * <p> The first byte read is stored into element <code>b[off]</code>, the
  17. * next one into <code>b[off+1]</code>, and so on. The number of bytes read
  18. * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of
  19. * bytes actually read; these bytes will be stored in elements
  20. * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>,
  21. * leaving elements <code>b[off+</code><i>k</i><code>]</code> through
  22. * <code>b[off+len-1]</code> unaffected.
  23. *
  24. * <p> In every case, elements <code>b[0]</code> through
  25. * <code>b[off]</code> and elements <code>b[off+len]</code> through
  26. * <code>b[b.length-1]</code> are unaffected.
  27. *
  28. * <p> The <code>read(b,</code> <code>off,</code> <code>len)</code> method
  29. * for class <code>InputStream</code> simply calls the method
  30. * <code>read()</code> repeatedly. If the first such call results in an
  31. * <code>IOException</code>, that exception is returned from the call to
  32. * the <code>read(b,</code> <code>off,</code> <code>len)</code> method. If
  33. * any subsequent call to <code>read()</code> results in a
  34. * <code>IOException</code>, the exception is caught and treated as if it
  35. * were end of file; the bytes read up to that point are stored into
  36. * <code>b</code> and the number of bytes read before the exception
  37. * occurred is returned. The default implementation of this method blocks
  38. * until the requested amount of input data <code>len</code> has been read,
  39. * end of file is detected, or an exception is thrown. Subclasses are encouraged
  40. * to provide a more efficient implementation of this method.
  41. *
  42. * @param b the buffer into which the data is read.
  43. * @param off the start offset in array <code>b</code>
  44. * at which the data is written.
  45. * @param len the maximum number of bytes to read.
  46. * @return the total number of bytes read into the buffer, or
  47. * <code>-1</code> if there is no more data because the end of
  48. * the stream has been reached.
  49. * @exception IOException If the first byte cannot be read for any reason
  50. * other than end of file, or if the input stream has been closed, or if
  51. * some other I/O error occurs.
  52. * @exception NullPointerException If <code>b</code> is <code>null</code>.
  53. * @exception IndexOutOfBoundsException If <code>off</code> is negative,
  54. * <code>len</code> is negative, or <code>len</code> is greater than
  55. * <code>b.length - off</code>
  56. * @see java.io.InputStream#read()
  57. */
  58. public int read(byte b[], int off, int len) throws IOException {
  59. if (b == null) {
  60. throw new NullPointerException();
  61. } else if (off < 0 || len < 0 || len > b.length - off) {
  62. throw new IndexOutOfBoundsException();
  63. } else if (len == 0) {
  64. return 0;
  65. }
  66. int c = read();
  67. if (c == -1) {
  68. return -1;
  69. }
  70. b[off] = (byte)c;
  71. int i = 1;
  72. try {
  73. for (; i < len ; i++) {
  74. c = read();
  75. if (c == -1) {
  76. break;
  77. }
  78. b[off + i] = (byte)c;
  79. }
  80. } catch (IOException ee) {
  81. }
  82. return i;
  83. }

skip

MAX_SKIP_BUFFER_SIZE 用于确定跳过时要使用的最大缓冲区大小。skip本身也是读操作,只不过不返回读到的数据,读到的数据也是通过读缓冲区来保存,只不过这里叫skipBuffer

跳过和丢弃此输入流中数据的 n 个字节。出于各种原因, skip 方法结束时跳过的字节数可能小于该数,也可能为 0。导致这种情况的原因很多,跳过 n 个字节之前已到达文件末尾只是其中一种可能。返回跳过的实际字节数。如果 n 为负,则不跳过任何字节。此类的 skip 方法创建一个 byte 数组,然后重复将字节读入其中,直到读够 n 个字节或已到达流末尾为止。建议子类提供此方法更为有效的实现。例如,可依赖搜索能力的实现。

  1. // MAX_SKIP_BUFFER_SIZE is used to determine the maximum buffer size to
  2. // use when skipping.
  3. private static final int MAX_SKIP_BUFFER_SIZE = 2048;
  4. /**
  5. * Skips over and discards <code>n</code> bytes of data from this input
  6. * stream. The <code>skip</code> method may, for a variety of reasons, end
  7. * up skipping over some smaller number of bytes, possibly <code>0</code>.
  8. * This may result from any of a number of conditions; reaching end of file
  9. * before <code>n</code> bytes have been skipped is only one possibility.
  10. * The actual number of bytes skipped is returned. If {@code n} is
  11. * negative, the {@code skip} method for class {@code InputStream} always
  12. * returns 0, and no bytes are skipped. Subclasses may handle the negative
  13. * value differently.
  14. *
  15. * <p> The <code>skip</code> method of this class creates a
  16. * byte array and then repeatedly reads into it until <code>n</code> bytes
  17. * have been read or the end of the stream has been reached. Subclasses are
  18. * encouraged to provide a more efficient implementation of this method.
  19. * For instance, the implementation may depend on the ability to seek.
  20. *
  21. * @param n the number of bytes to be skipped.
  22. * @return the actual number of bytes skipped.
  23. * @exception IOException if the stream does not support seek,
  24. * or if some other I/O error occurs.
  25. */
  26. public long skip(long n) throws IOException {
  27. long remaining = n;
  28. int nr;
  29. if (n <= 0) {
  30. return 0;
  31. }
  32. int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
  33. byte[] skipBuffer = new byte[size];
  34. while (remaining > 0) {
  35. nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
  36. if (nr < 0) {
  37. break;
  38. }
  39. remaining -= nr;
  40. }
  41. return n - remaining;
  42. }

available

返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。下一个调用可能是同一个线程,也可能是另一个线程。一次读取或跳过此估计数个字节不会受阻塞,但读取或跳过的字节数可能小于该数。注意,有些 InputStream 的实现将返回流中的字节总数,但也有很多实现不会这样做。试图使用此方法的返回值分配缓冲区,以保存此流所有数据的做法是不正确的。

如果已经调用 close() 方法关闭了此输入流,那么此方法的子类实现可以选择抛出 IOException。类 InputStream 的 available 方法总是返回 0。此方法应该由子类重写。

  1. /**
  2. * Returns an estimate of the number of bytes that can be read (or
  3. * skipped over) from this input stream without blocking by the next
  4. * invocation of a method for this input stream. The next invocation
  5. * might be the same thread or another thread. A single read or skip of this
  6. * many bytes will not block, but may read or skip fewer bytes.
  7. *
  8. * <p> Note that while some implementations of {@code InputStream} will return
  9. * the total number of bytes in the stream, many will not. It is
  10. * never correct to use the return value of this method to allocate
  11. * a buffer intended to hold all data in this stream.
  12. *
  13. * <p> A subclass' implementation of this method may choose to throw an
  14. * {@link IOException} if this input stream has been closed by
  15. * invoking the {@link #close()} method.
  16. *
  17. * <p> The {@code available} method for class {@code InputStream} always
  18. * returns {@code 0}.
  19. *
  20. * <p> This method should be overridden by subclasses.
  21. *
  22. * @return an estimate of the number of bytes that can be read (or skipped
  23. * over) from this input stream without blocking or {@code 0} when
  24. * it reaches the end of the input stream.
  25. * @exception IOException if an I/O error occurs.
  26. */
  27. public int available() throws IOException {
  28. return 0;
  29. }

mark

很多读数据的操作都会提供类似mark的方法,用来作为游标,在数据或记录中游走。并且会匹配reset的设计。

  1. 在此输入流中标记当前的位置。对 reset 方法的后续调用会在最后标记的位置重新定位此流,**以便后续回到该位置重新读取相同的字节**。readlimit 参数告知此输入流在标记位置失效之前允许读取的字节数。mark 的常规协定是:如果方法 markSupported 返回 true,那么输入流总是在调用 mark 之后记录所有读取的字节,并时刻准备在调用方法 reset 时(无论何时),再次提供这些相同的字节。但是,如果在调用 reset 之前可以从流中读取多于 readlimit 的字节,则不需要该流记录任何数据。**标记已关闭的流对其无效。InputStream mark 方法不执行任何操作。**
  1. /**
  2. * Marks the current position in this input stream. A subsequent call to
  3. * the <code>reset</code> method repositions this stream at the last marked
  4. * position so that subsequent reads re-read the same bytes.
  5. *
  6. * <p> The <code>readlimit</code> arguments tells this input stream to
  7. * allow that many bytes to be read before the mark position gets
  8. * invalidated.
  9. *
  10. * <p> The general contract of <code>mark</code> is that, if the method
  11. * <code>markSupported</code> returns <code>true</code>, the stream somehow
  12. * remembers all the bytes read after the call to <code>mark</code> and
  13. * stands ready to supply those same bytes again if and whenever the method
  14. * <code>reset</code> is called. However, the stream is not required to
  15. * remember any data at all if more than <code>readlimit</code> bytes are
  16. * read from the stream before <code>reset</code> is called.
  17. *
  18. * <p> Marking a closed stream should not have any effect on the stream.
  19. *
  20. * <p> The <code>mark</code> method of <code>InputStream</code> does
  21. * nothing.
  22. *
  23. * @param readlimit the maximum limit of bytes that can be read before
  24. * the mark position becomes invalid.
  25. * @see java.io.InputStream#reset()
  26. */
  27. public synchronized void mark(int readlimit) {}

markSupported

并非所有流都支持设置标记。测试此输入流是否支持 mark 和 reset 方法。是否支持 mark 和 reset 是特定输入流实例的不变属性。 InputStream 的 markSupported 方法返回 false。

  1. /**
  2. * Tests if this input stream supports the <code>mark</code> and
  3. * <code>reset</code> methods. Whether or not <code>mark</code> and
  4. * <code>reset</code> are supported is an invariant property of a
  5. * particular input stream instance. The <code>markSupported</code> method
  6. * of <code>InputStream</code> returns <code>false</code>.
  7. *
  8. * @return <code>true</code> if this stream instance supports the mark
  9. * and reset methods; <code>false</code> otherwise.
  10. * @see java.io.InputStream#mark(int)
  11. * @see java.io.InputStream#reset()
  12. */
  13. public boolean markSupported() {
  14. return false;
  15. }

reset

将此流重新定位到最后一次对此输入流调用 mark 方法时的位置。reset 的常规协定是:

  • 如果方法 markSupported 返回 true,那么:
    • 如果创建流以后未调用方法 mark,或最后调用 mark 以后从该流读取的字节数大于最后调用 mark 时的参数,则可能抛出 IOException。
    • 如果未抛出这样的 IOException,则将该流重新设置为这种状态:最近一次调用 mark 以后(如果未调用过 mark,则从文件开头开始)读取的所有字节将重新提供给 read 方法的后续调用者,后跟任何从调用 reset 时起将作为下一输入数据的字节。
  • 如果方法 markSupported 返回 false,那么:
    • 对 reset 的调用可能抛出 IOException。
    • 如果未抛出 IOException,则将该流重新设置为一种固定状态,该状态取决于输入流的特定类型及其创建方式。提供给 read 方法后续调用者的字节取决于特定类型的输入流。

除了抛出 IOException 之外,类 InputStream 的方法 reset 不执行任何操作。

  1. /**
  2. * Repositions this stream to the position at the time the
  3. * <code>mark</code> method was last called on this input stream.
  4. *
  5. * <p> The general contract of <code>reset</code> is:
  6. *
  7. * <ul>
  8. * <li> If the method <code>markSupported</code> returns
  9. * <code>true</code>, then:
  10. *
  11. * <ul><li> If the method <code>mark</code> has not been called since
  12. * the stream was created, or the number of bytes read from the stream
  13. * since <code>mark</code> was last called is larger than the argument
  14. * to <code>mark</code> at that last call, then an
  15. * <code>IOException</code> might be thrown.
  16. *
  17. * <li> If such an <code>IOException</code> is not thrown, then the
  18. * stream is reset to a state such that all the bytes read since the
  19. * most recent call to <code>mark</code> (or since the start of the
  20. * file, if <code>mark</code> has not been called) will be resupplied
  21. * to subsequent callers of the <code>read</code> method, followed by
  22. * any bytes that otherwise would have been the next input data as of
  23. * the time of the call to <code>reset</code>. </ul>
  24. *
  25. * <li> If the method <code>markSupported</code> returns
  26. * <code>false</code>, then:
  27. *
  28. * <ul><li> The call to <code>reset</code> may throw an
  29. * <code>IOException</code>.
  30. *
  31. * <li> If an <code>IOException</code> is not thrown, then the stream
  32. * is reset to a fixed state that depends on the particular type of the
  33. * input stream and how it was created. The bytes that will be supplied
  34. * to subsequent callers of the <code>read</code> method depend on the
  35. * particular type of the input stream. </ul></ul>
  36. *
  37. * <p>The method <code>reset</code> for class <code>InputStream</code>
  38. * does nothing except throw an <code>IOException</code>.
  39. *
  40. * @exception IOException if this stream has not been marked or if the
  41. * mark has been invalidated.
  42. * @see java.io.InputStream#mark(int)
  43. * @see java.io.IOException
  44. */
  45. public synchronized void reset() throws IOException {
  46. throw new IOException("mark/reset not supported");
  47. }

close

关闭此输入流并释放与该流关联的所有系统资源。InputStream 的 close 方法不执行任何操作。

  1. /**
  2. * Closes this input stream and releases any system resources associated
  3. * with the stream.
  4. *
  5. * <p> The <code>close</code> method of <code>InputStream</code> does
  6. * nothing.
  7. *
  8. * @exception IOException if an I/O error occurs.
  9. */
  10. public void close() throws IOException {}

输入流的子类

ByteArrayInputStream

这个类是一个字节数组输入流,数据是被读入内存中的字节数组。ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。关闭 ByteArrayInputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。

UML概述

image.png

重要方法

构造函数

  • buf[] - 由流的创建者提供的字节数组。元素 buf[0] 到 buf[count-1] 是唯一可以从流中读取的字节;元素 buf[pos] 是要读取的下一个字节。
  • pos - 要从输入流缓冲区读取的下一个字符的索引。该值应始终为非负且不大于计数值。要从输入流缓冲区读取的下一个字节将是 buf[pos]
  • mark - 流中当前标记的位置。 ByteArrayInputStream 对象在构造时默认标记在位置零。它们可以通过 mark() 方法在缓冲区内的另一个位置进行标记。当前缓冲区位置由 reset() 方法设置到这一点。如果未设置标记,则标记的值是传递给构造函数的偏移量(如果未提供偏移量,则为 0 )
  • count - 比输入流缓冲区中最后一个有效字符大一的索引。该值应始终为非负且不大于 buf 的长度。它比 buf 中可以从输入流缓冲区读取的最后一个字节的位置大 1。
  1. public
  2. class ByteArrayInputStream extends InputStream {
  3. /**
  4. * An array of bytes that was provided
  5. * by the creator of the stream. Elements <code>buf[0]</code>
  6. * through <code>buf[count-1]</code> are the
  7. * only bytes that can ever be read from the
  8. * stream; element <code>buf[pos]</code> is
  9. * the next byte to be read.
  10. */
  11. protected byte buf[];
  12. /**
  13. * The index of the next character to read from the input stream buffer.
  14. * This value should always be nonnegative
  15. * and not larger than the value of <code>count</code>.
  16. * The next byte to be read from the input stream buffer
  17. * will be <code>buf[pos]</code>.
  18. */
  19. protected int pos;
  20. /**
  21. * The currently marked position in the stream.
  22. * ByteArrayInputStream objects are marked at position zero by
  23. * default when constructed. They may be marked at another
  24. * position within the buffer by the <code>mark()</code> method.
  25. * The current buffer position is set to this point by the
  26. * <code>reset()</code> method.
  27. * <p>
  28. * If no mark has been set, then the value of mark is the offset
  29. * passed to the constructor (or 0 if the offset was not supplied).
  30. *
  31. * @since JDK1.1
  32. */
  33. protected int mark = 0;
  34. /**
  35. * The index one greater than the last valid character in the input
  36. * stream buffer.
  37. * This value should always be nonnegative
  38. * and not larger than the length of <code>buf</code>.
  39. * It is one greater than the position of
  40. * the last byte within <code>buf</code> that
  41. * can ever be read from the input stream buffer.
  42. */
  43. protected int count;
  44. /**
  45. * Creates <code>ByteArrayInputStream</code>
  46. * that uses <code>buf</code> as its
  47. * buffer array. The initial value of <code>pos</code>
  48. * is <code>offset</code> and the initial value
  49. * of <code>count</code> is the minimum of <code>offset+length</code>
  50. * and <code>buf.length</code>.
  51. * The buffer array is not copied. The buffer's mark is
  52. * set to the specified offset.
  53. *
  54. * @param buf the input buffer.
  55. * @param offset the offset in the buffer of the first byte to read.
  56. * @param length the maximum number of bytes to read from the buffer.
  57. */
  58. public ByteArrayInputStream(byte buf[], int offset, int length) {
  59. this.buf = buf;
  60. this.pos = offset;
  61. this.count = Math.min(offset + length, buf.length);
  62. this.mark = offset;
  63. }

read()

从此输入流中读取下一个数据字节。返回一个 0 到 255 范围内的 int 字节值。如果因为到达流末尾而没有可用的字节,则返回值 -1。此 read 方法不会阻塞。

  1. /**
  2. * Reads the next byte of data from this input stream. The value
  3. * byte is returned as an <code>int</code> in the range
  4. * <code>0</code> to <code>255</code>. If no byte is available
  5. * because the end of the stream has been reached, the value
  6. * <code>-1</code> is returned.
  7. * <p>
  8. * This <code>read</code> method
  9. * cannot block.
  10. *
  11. * @return the next byte of data, or <code>-1</code> if the end of the
  12. * stream has been reached.
  13. */
  14. public synchronized int read() {
  15. return (pos < count) ? (buf[pos++] & 0xff) : -1;
  16. }

读取一个字节的时候有些特别,需要将字节转成一个int值返回,并且是一个 0 到 255 范围内的无符号的数值。因此通过位运算 buf[pos++] & 0xff 进行无符号int的转换。
在byte 到 int 的无符号转换中,int 的高 24 位必须为零,低 8 位继续等于 byte 参数的位。

  1. public class Main {
  2. public static void main(String[] args) {
  3. byte b1 = (byte) 1;
  4. int i1 = (int) b1;
  5. System.out.println(i1); // 1
  6. System.out.println(Integer.toBinaryString(b1)); // 1
  7. byte b2 = (byte) 127;
  8. int i2 = (int) b2;
  9. System.out.println(i2); // 127
  10. System.out.println(Integer.toBinaryString(b2)); // 1111111
  11. byte b3 = (byte) 128;
  12. int i3 = (int) b3;
  13. System.out.println(i3); // -128
  14. System.out.println(Integer.toBinaryString(i3)); // 11111111111111111111111110000000
  15. // Integer.MAX_VALUE = 2147483647 = 2^31
  16. byte b4 = (byte) 128;
  17. int i4 = (int) (b4 & 0xff);
  18. System.out.println(i4); // 128
  19. }
  20. }

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

将最多 len 个数据字节从此输入流读入 byte 数组。如果 pos 等于 count,则返回 -1 指示文件结束。否则,读取的字节数 k 等于 len 和 count-pos 中的较小者。如果 k 是正数,则以 System.arraycopy 执行的方式将 buf[pos] 到 buf[pos+k-1] 的字节复制到 b[off] 到 b[off+k-1] 中。将值 k 与 pos 相加并返回 k。此 read 方法不会阻塞。

  1. /**
  2. * Reads up to <code>len</code> bytes of data into an array of bytes
  3. * from this input stream.
  4. * If <code>pos</code> equals <code>count</code>,
  5. * then <code>-1</code> is returned to indicate
  6. * end of file. Otherwise, the number <code>k</code>
  7. * of bytes read is equal to the smaller of
  8. * <code>len</code> and <code>count-pos</code>.
  9. * If <code>k</code> is positive, then bytes
  10. * <code>buf[pos]</code> through <code>buf[pos+k-1]</code>
  11. * are copied into <code>b[off]</code> through
  12. * <code>b[off+k-1]</code> in the manner performed
  13. * by <code>System.arraycopy</code>. The
  14. * value <code>k</code> is added into <code>pos</code>
  15. * and <code>k</code> is returned.
  16. * <p>
  17. * This <code>read</code> method cannot block.
  18. *
  19. * @param b the buffer into which the data is read.
  20. * @param off the start offset in the destination array <code>b</code>
  21. * @param len the maximum number of bytes read.
  22. * @return the total number of bytes read into the buffer, or
  23. * <code>-1</code> if there is no more data because the end of
  24. * the stream has been reached.
  25. * @exception NullPointerException If <code>b</code> is <code>null</code>.
  26. * @exception IndexOutOfBoundsException If <code>off</code> is negative,
  27. * <code>len</code> is negative, or <code>len</code> is greater than
  28. * <code>b.length - off</code>
  29. */
  30. public synchronized int read(byte b[], int off, int len) {
  31. if (b == null) {
  32. throw new NullPointerException();
  33. } else if (off < 0 || len < 0 || len > b.length - off) {
  34. throw new IndexOutOfBoundsException();
  35. }
  36. if (pos >= count) {
  37. return -1;
  38. }
  39. int avail = count - pos;
  40. if (len > avail) {
  41. len = avail;
  42. }
  43. if (len <= 0) {
  44. return 0;
  45. }
  46. System.arraycopy(buf, pos, b, off, len);
  47. pos += len;
  48. return len;
  49. }

skip

从此输入流中跳过 n 个输入字节。如果已到达输入流末尾,则可能会跳过较少的字节。实际跳过的字节数 k 等于 n 和 count-pos 中的较小者。将值 k 与 pos 相加并返回 k。

千言万语一句话,向后跳过n个位置,但是不要越界,如果会越界就跳到末尾就可以了。

  1. /**
  2. * Skips <code>n</code> bytes of input from this input stream. Fewer
  3. * bytes might be skipped if the end of the input stream is reached.
  4. * The actual number <code>k</code>
  5. * of bytes to be skipped is equal to the smaller
  6. * of <code>n</code> and <code>count-pos</code>.
  7. * The value <code>k</code> is added into <code>pos</code>
  8. * and <code>k</code> is returned.
  9. *
  10. * @param n the number of bytes to be skipped.
  11. * @return the actual number of bytes skipped.
  12. */
  13. public synchronized long skip(long n) {
  14. long k = count - pos;
  15. if (n < k) {
  16. k = n < 0 ? 0 : n;
  17. }
  18. pos += k;
  19. return k;
  20. }

available

返回可从此输入流读取(或跳过)的剩余字节数。返回值是 count - pos,它是要从输入缓冲区中读取的剩余字节数。

  1. /**
  2. * Returns the number of remaining bytes that can be read (or skipped over)
  3. * from this input stream.
  4. * <p>
  5. * The value returned is <code>count&nbsp;- pos</code>,
  6. * which is the number of bytes remaining to be read from the input buffer.
  7. *
  8. * @return the number of remaining bytes that can be read (or skipped
  9. * over) from this input stream without blocking.
  10. */
  11. public synchronized int available() {
  12. return count - pos;
  13. }

markSupported

测试此 InputStream 是否支持 mark/reset。 ByteArrayInputStream 的 markSupported 方法始终返回 true。

  1. /**
  2. * Tests if this <code>InputStream</code> supports mark/reset. The
  3. * <code>markSupported</code> method of <code>ByteArrayInputStream</code>
  4. * always returns <code>true</code>.
  5. *
  6. * @since JDK1.1
  7. */
  8. public boolean markSupported() {
  9. return true;
  10. }

mark

设置流中的当前标记位置。构造时默认将 ByteArrayInputStream 对象标记在位置零处。通过此方法可将其标记在缓冲区内的另一个位置处。如果尚未设置标记,则标记值是传递给构造方法的偏移量(如果未提供偏移量,则标记值为 0)。注:readAheadLimit 对于此类没有意义。

  1. /**
  2. * Set the current marked position in the stream.
  3. * ByteArrayInputStream objects are marked at position zero by
  4. * default when constructed. They may be marked at another
  5. * position within the buffer by this method.
  6. * <p>
  7. * If no mark has been set, then the value of the mark is the
  8. * offset passed to the constructor (or 0 if the offset was not
  9. * supplied).
  10. *
  11. * <p> Note: The <code>readAheadLimit</code> for this class
  12. * has no meaning.
  13. *
  14. * @since JDK1.1
  15. */
  16. public void mark(int readAheadLimit) {
  17. mark = pos;
  18. }

reset

将缓冲区的位置重置为标记位置。除非已标记了另一个位置,或者在构造方法中指定了一个偏移量,否则该标记位置是 0。

  1. /**
  2. * Resets the buffer to the marked position. The marked position
  3. * is 0 unless another position was marked or an offset was specified
  4. * in the constructor.
  5. */
  6. public synchronized void reset() {
  7. pos = mark;
  8. }

FilterInputStream

FilterInputStream 包含其他一些输入流,它将这些流用作其基本数据源,它可以直接传输数据或提供一些额外的功能。FilterInputStream 类本身只是简单地重写那些将所有请求传递给所包含输入流的 InputStream 的所有方法。FilterInputStream 的子类可进一步重写这些方法中的一些方法,并且还可以提供一些额外的方法和字段。

千言万语一句话就是用来对数据进行过滤拦截的用的,在数据的处理过程中对数据做一些额外的操作,数据经过一层一层的过滤器,被逐层处理,比如被缓冲,被压缩,被加密,或者什么都不做只是打印一下log,这是一种很常见的设计方式,比如MINA中的Filter等等。

UML概述

image.png

重要方法

构造函数

用一个外部的输入流来包装或者说是装饰一个内部输入流。大家可能知道IO是基于装饰器模式。而装饰器模式和代理模式看上去很相似,一般来说代理模式中代理类和被代理类之间的角色定义很明确。而装饰器模式中装饰器的装饰顺序并没有明确或固定的叠加顺序,非常灵活,甚至可以重复叠加,比如一个计算折扣的装饰器,被连续嵌套两次,就相当于折上折。当然也有一些装饰器需要遵循顺序,比如先缓冲区装饰器需要先写入缓冲区,再写入底层文件系统。

  1. public
  2. class FilterInputStream extends InputStream {
  3. /**
  4. * The input stream to be filtered.
  5. */
  6. protected volatile InputStream in;
  7. /**
  8. * Creates a <code>FilterInputStream</code>
  9. * by assigning the argument <code>in</code>
  10. * to the field <code>this.in</code> so as
  11. * to remember it for later use.
  12. *
  13. * @param in the underlying input stream, or <code>null</code> if
  14. * this instance is to be created without an underlying stream.
  15. */
  16. protected FilterInputStream(InputStream in) {
  17. this.in = in;
  18. }

read

从此输入流中读取下一个数据字节。返回一个 0255 范围内的 int 字节值。如果因为已经到达流末尾而没有字节可用,则返回 -1。在输入数据可用、检测到流末尾或抛出异常之前,此方法将一直阻塞。此方法只执行 in.read() 并返回结果。

  1. /**
  2. * Reads the next byte of data from this input stream. The value
  3. * byte is returned as an <code>int</code> in the range
  4. * <code>0</code> to <code>255</code>. If no byte is available
  5. * because the end of the stream has been reached, the value
  6. * <code>-1</code> is returned. This method blocks until input data
  7. * is available, the end of the stream is detected, or an exception
  8. * is thrown.
  9. * <p>
  10. * This method
  11. * simply performs <code>in.read()</code> and returns the result.
  12. *
  13. * @return the next byte of data, or <code>-1</code> if the end of the
  14. * stream is reached.
  15. * @exception IOException if an I/O error occurs.
  16. * @see java.io.FilterInputStream#in
  17. */
  18. public int read() throws IOException {
  19. return in.read();
  20. }


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

从此输入流中将 len 个字节的数据读入一个 byte 数组中。如果 len 不为 0,则在输入可用前,此方法将阻塞;否则,不读取任何字节并且返回 0。此方法只执行 in.read(b, off, len) 并返回结果。

  1. /**
  2. * Reads up to <code>len</code> bytes of data from this input stream
  3. * into an array of bytes. If <code>len</code> is not zero, the method
  4. * blocks until some input is available; otherwise, no
  5. * bytes are read and <code>0</code> is returned.
  6. * <p>
  7. * This method simply performs <code>in.read(b, off, len)</code>
  8. * and returns the result.
  9. *
  10. * @param b the buffer into which the data is read.
  11. * @param off the start offset in the destination array <code>b</code>
  12. * @param len the maximum number of bytes read.
  13. * @return the total number of bytes read into the buffer, or
  14. * <code>-1</code> if there is no more data because the end of
  15. * the stream has been reached.
  16. * @exception NullPointerException If <code>b</code> is <code>null</code>.
  17. * @exception IndexOutOfBoundsException If <code>off</code> is negative,
  18. * <code>len</code> is negative, or <code>len</code> is greater than
  19. * <code>b.length - off</code>
  20. * @exception IOException if an I/O error occurs.
  21. * @see java.io.FilterInputStream#in
  22. */
  23. public int read(byte b[], int off, int len) throws IOException {
  24. return in.read(b, off, len);
  25. }

skip

跳过和丢弃此输入流中数据的 n 个字节。出于各种原因, skip 方法结束时跳过的字节数可能小于该数,也可能为 0。导致这种情况的原因很多,跳过 n 个字节之前已到达文件末尾只是其中一种可能。返回跳过的实际字节数。如果 n 为负,则不跳过任何字节。
此类的 skip 方法创建一个 byte 数组,然后重复将字节读入其中,直到读够 n 个字节或已到达流末尾为止。建议子类提供此方法更为有效的实现。例如,可依赖搜索能力的实现。
此方法只执行 in.skip(n)

  1. /**
  2. * Skips over and discards <code>n</code> bytes of data from the
  3. * input stream. The <code>skip</code> method may, for a variety of
  4. * reasons, end up skipping over some smaller number of bytes,
  5. * possibly <code>0</code>. The actual number of bytes skipped is
  6. * returned.
  7. * <p>
  8. * This method simply performs <code>in.skip(n)</code>.
  9. *
  10. * @param n the number of bytes to be skipped.
  11. * @return the actual number of bytes skipped.
  12. * @exception IOException if the stream does not support seek,
  13. * or if some other I/O error occurs.
  14. */
  15. public long skip(long n) throws IOException {
  16. return in.skip(n);
  17. }

available

返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。下一个调用者可能是同一个线程,也可能是另一个线程。一次读取或跳过此数量个字节不会发生阻塞,但读取或跳过的字节可能小于该数。此方法返回 [in](https://tool.oschina.net/uploads/apidocs/jdk-zh/java/io/FilterInputStream.html#in).available() 的结果。

  1. /**
  2. * Returns an estimate of the number of bytes that can be read (or
  3. * skipped over) from this input stream without blocking by the next
  4. * caller of a method for this input stream. The next caller might be
  5. * the same thread or another thread. A single read or skip of this
  6. * many bytes will not block, but may read or skip fewer bytes.
  7. * <p>
  8. * This method returns the result of {@link #in in}.available().
  9. *
  10. * @return an estimate of the number of bytes that can be read (or skipped
  11. * over) from this input stream without blocking.
  12. * @exception IOException if an I/O error occurs.
  13. */
  14. public int available() throws IOException {
  15. return in.available();
  16. }

close

关闭此输入流并释放与此流关联的所有系统资源。此方法只执行 in.close()

  1. /**
  2. * Closes this input stream and releases any system resources
  3. * associated with the stream.
  4. * This
  5. * method simply performs <code>in.close()</code>.
  6. *
  7. * @exception IOException if an I/O error occurs.
  8. * @see java.io.FilterInputStream#in
  9. */
  10. public void close() throws IOException {
  11. in.close();
  12. }

mark

在输入流中的当前位置上作标记。 reset 方法的后续调用将此流重新定位在最后标记的位置上,以便后续读取操作重新读取相同的字节。readlimit 参数告知此输入流在标记位置无效之前允许读取的字节数。此方法只执行 in.mark(readlimit)

  1. /**
  2. * Marks the current position in this input stream. A subsequent
  3. * call to the <code>reset</code> method repositions this stream at
  4. * the last marked position so that subsequent reads re-read the same bytes.
  5. * <p>
  6. * The <code>readlimit</code> argument tells this input stream to
  7. * allow that many bytes to be read before the mark position gets
  8. * invalidated.
  9. * <p>
  10. * This method simply performs <code>in.mark(readlimit)</code>.
  11. *
  12. * @param readlimit the maximum limit of bytes that can be read before
  13. * the mark position becomes invalid.
  14. * @see java.io.FilterInputStream#in
  15. * @see java.io.FilterInputStream#reset()
  16. */
  17. public synchronized void mark(int readlimit) {
  18. in.mark(readlimit);
  19. }

reset

将此流重新定位到对此输入流最后调用 mark 方法时的位置。此方法只执行 in.reset()。在需要提前读取一小部分数据以查看流中有什么的情况下,可以使用流的标记。通过调用通用解析器常常最容易做到这一点。如果流属于通过解析处理的类型,那么解析起来就很容易。如果流不属于那种类型,那么解析器应该在解析失败时抛出一个异常。如果这发生在 readlimit 个字节内,那么它允许外部代码重置流,并尝试另一种解析器。

  1. /**
  2. * Repositions this stream to the position at the time the
  3. * <code>mark</code> method was last called on this input stream.
  4. * <p>
  5. * This method
  6. * simply performs <code>in.reset()</code>.
  7. * <p>
  8. * Stream marks are intended to be used in
  9. * situations where you need to read ahead a little to see what's in
  10. * the stream. Often this is most easily done by invoking some
  11. * general parser. If the stream is of the type handled by the
  12. * parse, it just chugs along happily. If the stream is not of
  13. * that type, the parser should toss an exception when it fails.
  14. * If this happens within readlimit bytes, it allows the outer
  15. * code to reset the stream and try another parser.
  16. *
  17. * @exception IOException if the stream has not been marked or if the
  18. * mark has been invalidated.
  19. * @see java.io.FilterInputStream#in
  20. * @see java.io.FilterInputStream#mark(int)
  21. */
  22. public synchronized void reset() throws IOException {
  23. in.reset();
  24. }

markSupported

测试此输入流是否支持 markreset 方法。此方法只执行 in.markSupported()

  1. /**
  2. * Tests if this input stream supports the <code>mark</code>
  3. * and <code>reset</code> methods.
  4. * This method
  5. * simply performs <code>in.markSupported()</code>.
  6. *
  7. * @return <code>true</code> if this stream type supports the
  8. * <code>mark</code> and <code>reset</code> method;
  9. * <code>false</code> otherwise.
  10. * @see java.io.FilterInputStream#in
  11. * @see java.io.InputStream#mark(int)
  12. * @see java.io.InputStream#reset()
  13. */
  14. public boolean markSupported() {
  15. return in.markSupported();
  16. }

BufferedInputStream

BufferedInputStream 为另一个输入流添加一些功能,即缓冲输入以及支持 mark 和 reset 方法的能力。在创建 BufferedInputStream 时,会创建一个内部缓冲区数组。在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。mark 操作记录输入流中的某个点,reset 操作使得在从包含的输入流中获取新字节之前,再次读取自最后一次 mark 操作后读取的所有字节。

UML概述

image.png

重要方法

构造函数

创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。创建一个长度为 size 的内部缓冲区数组并将其存储在 buf 中。

  1. public
  2. class BufferedInputStream extends FilterInputStream {
  3. private static int DEFAULT_BUFFER_SIZE = 8192;
  4. /**
  5. * The maximum size of array to allocate.
  6. * Some VMs reserve some header words in an array.
  7. * Attempts to allocate larger arrays may result in
  8. * OutOfMemoryError: Requested array size exceeds VM limit
  9. */
  10. private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
  11. /**
  12. * Creates a <code>BufferedInputStream</code>
  13. * with the specified buffer size,
  14. * and saves its argument, the input stream
  15. * <code>in</code>, for later use. An internal
  16. * buffer array of length <code>size</code>
  17. * is created and stored in <code>buf</code>.
  18. *
  19. * @param in the underlying input stream.
  20. * @param size the buffer size.
  21. * @exception IllegalArgumentException if {@code size <= 0}.
  22. */
  23. public BufferedInputStream(InputStream in, int size) {
  24. super(in);
  25. if (size <= 0) {
  26. throw new IllegalArgumentException("Buffer size <= 0");
  27. }
  28. buf = new byte[size];
  29. }

read

返回缓冲区中的下一个数据字节,如果到达流末尾,则返回 -1

  1. /**
  2. * See
  3. * the general contract of the <code>read</code>
  4. * method of <code>InputStream</code>.
  5. *
  6. * @return the next byte of data, or <code>-1</code> if the end of the
  7. * stream is reached.
  8. * @exception IOException if this input stream has been closed by
  9. * invoking its {@link #close()} method,
  10. * or an I/O error occurs.
  11. * @see java.io.FilterInputStream#in
  12. */
  13. public synchronized int read() throws IOException {
  14. if (pos >= count) {
  15. fill();
  16. if (pos >= count)
  17. return -1;
  18. }
  19. return getBufIfOpen()[pos++] & 0xff;
  20. }

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

从此字节输入流中给定偏移量处开始将各字节读取到指定的 byte 数组中。
此方法实现了 [InputStream](https://tool.oschina.net/uploads/apidocs/jdk-zh/java/io/InputStream.html) 类相应 [read](https://tool.oschina.net/uploads/apidocs/jdk-zh/java/io/InputStream.html#read(byte[],%20int,%20int)) 方法的常规协定。另一个便捷之处在于,它将通过重复地调用底层流的 read 方法,尝试读取尽可能多的字节。这种迭代的 read 会一直继续下去,直到满足以下条件之一:

  • 已经读取了指定的字节数,
  • 底层流的 read 方法返回 -1,指示文件末尾(end-of-file),或者
  • 底层流的 available 方法返回 0,指示将阻塞后续的输入请求。

如果第一次对底层流调用 read 返回 -1(指示文件末尾),则此方法返回 -1。否则此方法返回实际读取的字节数。鼓励(但不是必须)此类的各个子类以相同的方式尝试读取尽可能多的字节。

  1. /**
  2. * Reads bytes from this byte-input stream into the specified byte array,
  3. * starting at the given offset.
  4. *
  5. * <p> This method implements the general contract of the corresponding
  6. * <code>{@link InputStream#read(byte[], int, int) read}</code> method of
  7. * the <code>{@link InputStream}</code> class. As an additional
  8. * convenience, it attempts to read as many bytes as possible by repeatedly
  9. * invoking the <code>read</code> method of the underlying stream. This
  10. * iterated <code>read</code> continues until one of the following
  11. * conditions becomes true: <ul>
  12. *
  13. * <li> The specified number of bytes have been read,
  14. *
  15. * <li> The <code>read</code> method of the underlying stream returns
  16. * <code>-1</code>, indicating end-of-file, or
  17. *
  18. * <li> The <code>available</code> method of the underlying stream
  19. * returns zero, indicating that further input requests would block.
  20. *
  21. * </ul> If the first <code>read</code> on the underlying stream returns
  22. * <code>-1</code> to indicate end-of-file then this method returns
  23. * <code>-1</code>. Otherwise this method returns the number of bytes
  24. * actually read.
  25. *
  26. * <p> Subclasses of this class are encouraged, but not required, to
  27. * attempt to read as many bytes as possible in the same fashion.
  28. *
  29. * @param b destination buffer.
  30. * @param off offset at which to start storing bytes.
  31. * @param len maximum number of bytes to read.
  32. * @return the number of bytes read, or <code>-1</code> if the end of
  33. * the stream has been reached.
  34. * @exception IOException if this input stream has been closed by
  35. * invoking its {@link #close()} method,
  36. * or an I/O error occurs.
  37. */
  38. public synchronized int read(byte b[], int off, int len)
  39. throws IOException
  40. {
  41. getBufIfOpen(); // Check for closed stream
  42. if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
  43. throw new IndexOutOfBoundsException();
  44. } else if (len == 0) {
  45. return 0;
  46. }
  47. int n = 0;
  48. for (;;) {
  49. int nread = read1(b, off + n, len - n);
  50. if (nread <= 0)
  51. return (n == 0) ? nread : n;
  52. n += nread;
  53. if (n >= len)
  54. return n;
  55. // if not closed but no bytes available, return
  56. InputStream input = in;
  57. if (input != null && input.available() <= 0)
  58. return n;
  59. }
  60. }

available

返回可以从此输入流读取(或跳过)、且不受此输入流接下来的方法调用阻塞的估计字节数。接下来的调用可能是同一个线程,也可能是不同的线程。一次读取或跳过这么多字节将不会受阻塞,但可以读取或跳过数量更少的字节。此方法返回缓冲区中剩余的待读取字节数 (count - pos) 与调用 in.available() 的结果之和。

千言万语一句话就是 available 等于 当前输入流自身缓冲区的available(count - pos) + 底层输入流的available 就是整体的available。包装类和被包装类各管各的available,重量就是它们之和。

  1. /**
  2. * Returns an estimate of the number of bytes that can be read (or
  3. * skipped over) from this input stream without blocking by the next
  4. * invocation of a method for this input stream. The next invocation might be
  5. * the same thread or another thread. A single read or skip of this
  6. * many bytes will not block, but may read or skip fewer bytes.
  7. * <p>
  8. * This method returns the sum of the number of bytes remaining to be read in
  9. * the buffer (<code>count&nbsp;- pos</code>) and the result of calling the
  10. * {@link java.io.FilterInputStream#in in}.available().
  11. *
  12. * @return an estimate of the number of bytes that can be read (or skipped
  13. * over) from this input stream without blocking.
  14. * @exception IOException if this input stream has been closed by
  15. * invoking its {@link #close()} method,
  16. * or an I/O error occurs.
  17. */
  18. public synchronized int available() throws IOException {
  19. int n = count - pos;
  20. int avail = getInIfOpen().available();
  21. return n > (Integer.MAX_VALUE - avail)
  22. ? Integer.MAX_VALUE
  23. : n + avail;
  24. }

mark

设置一个mark,rest的时候可以回到这里。readlimit - 在mark位置变为无效之前可以读取字节的最大限制。

  1. /**
  2. * See the general contract of the <code>mark</code>
  3. * method of <code>InputStream</code>.
  4. *
  5. * @param readlimit the maximum limit of bytes that can be read before
  6. * the mark position becomes invalid.
  7. * @see java.io.BufferedInputStream#reset()
  8. */
  9. public synchronized void mark(int readlimit) {
  10. marklimit = readlimit;
  11. markpos = pos;
  12. }

reset

如果 markpos-1(尚未设置标记,或者标记已失效),则抛出 IOException。否则将 pos 设置为与 markpos 相等。

  1. /**
  2. * See the general contract of the <code>reset</code>
  3. * method of <code>InputStream</code>.
  4. * <p>
  5. * If <code>markpos</code> is <code>-1</code>
  6. * (no mark has been set or the mark has been
  7. * invalidated), an <code>IOException</code>
  8. * is thrown. Otherwise, <code>pos</code> is
  9. * set equal to <code>markpos</code>.
  10. *
  11. * @exception IOException if this stream has not been marked or,
  12. * if the mark has been invalidated, or the stream
  13. * has been closed by invoking its {@link #close()}
  14. * method, or an I/O error occurs.
  15. * @see java.io.BufferedInputStream#mark(int)
  16. */
  17. public synchronized void reset() throws IOException {
  18. getBufIfOpen(); // Cause exception if closed
  19. if (markpos < 0)
  20. throw new IOException("Resetting to invalid mark");
  21. pos = markpos;
  22. }

markSupported

测试此输入流是否支持 markreset 方法。 BufferedInputStreammarkSupported 方法返回 true

  1. /**
  2. * Tests if this input stream supports the <code>mark</code>
  3. * and <code>reset</code> methods. The <code>markSupported</code>
  4. * method of <code>BufferedInputStream</code> returns
  5. * <code>true</code>.
  6. *
  7. * @return a <code>boolean</code> indicating if this stream type supports
  8. * the <code>mark</code> and <code>reset</code> methods.
  9. * @see java.io.InputStream#mark(int)
  10. * @see java.io.InputStream#reset()
  11. */
  12. public boolean markSupported() {
  13. return true;
  14. }

close

关闭此输入流并释放与该流关联的所有系统资源。关闭了该流之后,后续的 read()、available()、reset() 或 skip() 调用都将抛出 IOException。关闭之前已关闭的流不会产生任何效果。

  1. /**
  2. * Closes this input stream and releases any system resources
  3. * associated with the stream.
  4. * Once the stream has been closed, further read(), available(), reset(),
  5. * or skip() invocations will throw an IOException.
  6. * Closing a previously closed stream has no effect.
  7. *
  8. * @exception IOException if an I/O error occurs.
  9. */
  10. public void close() throws IOException {
  11. byte[] buffer;
  12. while ( (buffer = buf) != null) {
  13. if (bufUpdater.compareAndSet(this, buffer, null)) {
  14. InputStream input = in;
  15. in = null;
  16. if (input != null)
  17. input.close();
  18. return;
  19. }
  20. // Else retry in case a new buf was CASed in fill()
  21. }
  22. }