Writer      :BYSocket(泥沙砖瓦浆木匠)

微         博:BYSocket

豆         瓣:BYSocket

FaceBook:BYSocket

Twitter    :BYSocket

一、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

3. 泥瓦匠学习的代码都在github上(同步osc git),欢迎大家点star,提意见,一起进步。地址:https://github.com/JeffLi1993

Java IO 之 InputStream源码的更多相关文章

  1. Java IO 之 OutputStream源码

    Writer      :BYSocket(泥沙砖瓦浆木匠) 微         博:BYSocket 豆         瓣:BYSocket FaceBook:BYSocket Twitter   ...

  2. JAVA上百实例源码以及开源项目

    简介 笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级.中级.高级等,详情看源码列表,需要的可以直接下载! 这些源码反映了那时那景笔者对未来的盲目,对代码的热情.执着,对IT的憧憬. ...

  3. Java IO (1) - InputStream

    Java IO (1) - InputStream 前言 JavaIO一共包括两种,一种是stream,一种是reader/writer,每种又包括in/out,所以一共是四种包.Java 流在处理上 ...

  4. JAVA上百实例源码网站

    JAVA源码包1JAVA源码包2JAVA源码包3JAVA源码包4 JAVA开源包1 JAVA开源包2 JAVA开源包3 JAVA开源包4 JAVA开源包5 JAVA开源包6 JAVA开源包7 JAVA ...

  5. 死磕 java集合之CopyOnWriteArraySet源码分析——内含巧妙设计

    问题 (1)CopyOnWriteArraySet是用Map实现的吗? (2)CopyOnWriteArraySet是有序的吗? (3)CopyOnWriteArraySet是并发安全的吗? (4)C ...

  6. 死磕 java集合之LinkedHashSet源码分析

    问题 (1)LinkedHashSet的底层使用什么存储元素? (2)LinkedHashSet与HashSet有什么不同? (3)LinkedHashSet是有序的吗? (4)LinkedHashS ...

  7. 死磕Java之聊聊HashSet源码(基于JDK1.8)

    HashSet的UML图 HashSet的成员变量及其含义 public class HashSet<E> extends AbstractSet<E> implements ...

  8. Java集合---Array类源码解析

    Java集合---Array类源码解析              ---转自:牛奶.不加糖 一.Arrays.sort()数组排序 Java Arrays中提供了对所有类型的排序.其中主要分为Prim ...

  9. java线程池ThreadPoolExector源码分析

    java线程池ThreadPoolExector源码分析 今天研究了下ThreadPoolExector源码,大致上总结了以下几点跟大家分享下: 一.ThreadPoolExector几个主要变量 先 ...

随机推荐

  1. 【Leetcode】【Medium】word search

    Given a 2D board and a word, find if the word exists in the grid. The word can be constructed from l ...

  2. GoogleApis 屏蔽

    . 需要maven包,但是官方库里面,引用了googleapis的一些文件.因为gfw,慢的要死,拖垮了整个页面. 查了一下,在hosts修改googleapis解析时候的ip就好了: 把Google ...

  3. Python模拟HTTP Post上传文件

    使用urllib2模块构造http post数据结构,提交有文件的表单(multipart/form-data),本示例提交的post表单带有两个参数及一张图片,代码如下: #buld post bo ...

  4. servlet servlet请求与响应

    request 客户端浏览器发出的请求被封装成一个HttpServletRequest对象.所有的信息包括请求的地址,请求的参数,提交的数据,上传的文件,客户端的Ip地址甚至客户端操作系统都包含在Ht ...

  5. 【Android Studio】Android Studio 安装及设置

    版权所有, 禁止转载, 如有需要, 请站内联系. 本文地址: http://blog.csdn.net/caroline_wendy/article/details/20845807 时间: 2014 ...

  6. Leetcode 38 Count and Say 传说中的递推

    class Solution { public: vector<string> vs_; Solution(){ "); vs_.push_back(t); ; i< ;+ ...

  7. Leetcode 52 N-Queens II 回溯搜索

    对于N-Queens的每种情况,回答出每种情况的N-Queens的排列数. l,r和c是每种类型的格子是否有棋子. l判断的是这样的对角线的格子                   r判断的是这样的对 ...

  8. MySQL基础操作(一)

    1. 连接数据库mysql -h localhost -u root -p 123456 2. 查看数据库版本select version(); 3. 查看数据库支持的存储引擎和当前默认存储引擎sho ...

  9. hdu4508 完全背包,湫湫系列故事——减肥记I

    湫湫系列故事——减肥记I 对于01背包和完全背包,昨晚快睡着的时候,突然就来了灵感 区别:dp[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值 在第二重循环,01 是倒着循环的,因 ...

  10. hdu1879 继续畅通工程

    http://acm.hdu.edu.cn/showproblem.php?pid=1879 New~ 欢迎“热爱编程”的高考少年——报考杭州电子科技大学计算机学院关于2015年杭电ACM暑期集训队的 ...