欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程语言 > java >内容正文

java

Java IO 之 InputStream源码

发布时间:2025/3/19 java 40 豆豆
生活随笔 收集整理的这篇文章主要介绍了 Java IO 之 InputStream源码 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

一、InputStream

InputStream是一个抽象类,即表示所有字节输入流实现类的基类。它的作用就是抽象地表示所有从不同数据源产生输入的类,例如常见的FileInputStream、FilterInputStream等。那些数据源呢?比如:

1) 字节数组(不代表String类,但可以转换)

2) String对象

3) 文件

4) 一个其他种类的流组成的序列化 (在分布式系统中常见)

5) 管道(多线程环境中的数据源)

等等

二者,注意它是属于字节流部分,而不是字符流(java.io中Reader\Writer,下面会讲到)。

FilterInputStream是为各种InputStream实现类提供的“装饰器模式”的基类。因此,可以分为原始的字节流和“装饰”过的功能封装字节流。

 

二、细解InputStream源码的核心

源码如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 /**  * 所有字节输入流实现类的基类  */ public abstract class SInputStream {     // 缓存区字节数组最大值     private static final int MAX_SKIP_BUFFER_SIZE = 2048;     // 从输入流中读取数据的下一个字节,以int返回     public abstract int read() throws IOException;     // 从输入流中读取数据的一定数量字节,并存储在缓存数组b     public int read(byte b[]) throws IOException {         return read(b, 0, b.length);     }     // 从输入流中读取数据最多len个字节,并存储在缓存数组b     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个字节     public long skip(long n) throws IOException {         long remaining = n;         int nr;         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;         }         return n - remaining;     }     // 返回下一个方法调用能不受阻塞地从此读取(或者跳过)的估计字节数     public int available() throws IOException {         return 0;     }     // 关闭此输入流,并释放与其关联的所有资源     public void close() throws IOException {}     // 在此输出流中标记当前位置     public synchronized void mark(int readlimit) {}     // 将此流重新定位到最后一次对此输入流调用 mark 方法时的位置。     public synchronized void reset() throws IOException {         throw new IOException("mark/reset not supported");     }     // 测试此输入流是否支持 mark 和 reset 方法     public boolean markSupported() {         return false;     } }

其中,InputStream下面三个read方法才是核心方法:

1 public abstract int read()

抽象方法,没有具体实现。因为子类必须实现此方法的一个实现。这就是输入流的关键方法。

二者,可见下面两个read()方法都调用了这个方法子类的实现来完成功能的。

 

 

1 public int read(byte b[])

该方法是表示从输入流中读取数据的一定数量字节,并存储在缓存字节数组b。其效果等同于调用了下面方法的实现:

1 read(b, 0, b.length)

如果b的长度为 0,则不读取任何字节并返回 0;否则,尝试读取至少 1 字节。如果因为流位于文件末尾而没有可用的字节,则返回值 -1;否则,至少读取一个字节并将其存储在 b 中。

思考:这时候,怪不得很多时候, b != –1 或者 b != EOF

 

 

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


在输入数据可用、检测到流末尾或者抛出异常前,此方法一直阻塞。

该方法先进行校验,然后校验下个字节是否为空。如果校验通过后,
如下代码:

1 2 3 4 5 6 7 8 9 10 11 int i = 1; try {     for (; i < len ; i++) {         c = read();         if (c == -1) {             break;         }         b[off + i] = (byte)c;     } } catch (IOException ee) { }

将读取的第一个字节存储在元素 b[off] 中,下一个存储在 b[off+1] 中,依次类推。读取的字节数最多等于 len。设 k 为实际读取的字节数;这些字节将存储在 b[off] 到 b[off+k-1] 的元素中,不影响 b[off+k] 到 b[off+len-1] 的元素。



 

因为有上面两个read的实现,所以这里InputStream设计为抽象类。 

三、小结

1. InputSream 对应着 OutputStream

2. 看源码是享受人家写代码中流露的How

与50位技术专家面对面20年技术见证,附赠技术全景图

总结

以上是生活随笔为你收集整理的Java IO 之 InputStream源码的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。