Java IO - SequenceInputStream

基本概念

  • 作用:当我们需要从多个输入流读取数据时,就可以使用合并流(SequenceInputStream)将其合并一个输入流。

  • 特性:合并流会按照添加的顺序从第一个输入流开始读取,到最后一个输入流结束。

  • 继承:SequenceInputStream 同样地也继承自 InputStream


实例探究

1.将两个输入流合并

public static void main(String[] args) throws Exception {

    OutputStream os = new FileOutputStream(new File("E:" + File.separator + "os.txt"));
    InputStream is1 = new FileInputStream(new File("E:" + File.separator + "is1.txt"));
    InputStream is2 = new FileInputStream(new File("E:" + File.separator + "is2.txt"));

    //关键 --> 将两个输入添加进合并流
    SequenceInputStream sis = new SequenceInputStream(is1, is2);

    //按字节数组读取
    byte[] buffer = new byte[1024];
    int count = 0;
    while ((count = sis.read(buffer)) != -1) {
        os.write(buffer, 0, count);
    }

    os.flush();
    os.close();
    sis.close();
}

观察以上的代码,实现了将两个输入流通过合并流合并成了一个输入流(即将两个 txt 的内容,合并到一个 txt 中),然后再通过输出流进行输出。但这里有个限制,就是每次只允许两个输入流进行合并。若存在多个输入流呢?请接着往下看…


2.将多个输入流合并

public static void main(String[] args) throws Exception {

    OutputStream os = new FileOutputStream(new File("E:" + File.separator + "os.txt"));
    InputStream is1 = new FileInputStream(new File("E:" + File.separator + "is1.txt"));
    InputStream is2 = new FileInputStream(new File("E:" + File.separator + "is2.txt"));
    InputStream is3 = new FileInputStream(new File("E:" + File.separator + "is3.txt"));

    //关键 --> 通过 Vector 添加多个输入流
    Vector<InputStream> vector = new Vector<InputStream>(3);
    vector.add(is1);
    vector.add(is2);
    vector.add(is3);

    //将多个输入流添加进合并流
    Enumeration<InputStream> en = vector.elements();
    SequenceInputStream sis = new SequenceInputStream(en);

    //按字节数组读取
    byte[] buffer = new byte[1024];
    int count = 0;
    while ((count = sis.read(buffer)) != -1) {
        os.write(buffer, 0, count);
    }

    os.flush();
    os.close();
    sis.close();
}

观察以上的代码,发现通过向 Vector 中添加多个输入流,就可以不受数量的限制,实现多个输入流的合并。


源码分析

类结构图

结构


成员变量

//代表添加进 Vector 的所有输入流
Enumeration e;  

//代码当前进行操作的输入流
InputStream in; 

构造函数,这里定义了 2 个构造函数,分别对用两个输入流以及多个输入流的操作。

// ①允许多个输入流的合并
public SequenceInputStream(Enumeration<? extends InputStream> e) {
    this.e = e;
    try {
        nextStream();
    } catch (IOException ex) {
        // This should never happen
        throw new Error("panic");
    }
}

// ②允许两个输入流的合并
public SequenceInputStream(InputStream s1, InputStream s2) {
    Vector v = new Vector(2);
    v.addElement(s1);
    v.addElement(s2);
    e = v.elements();
    try {
        nextStream();
    } catch (IOException ex) {
        // This should never happen
        throw new Error("panic");
    }
}

观察它的构造方法,可以看到不论是调用哪种构造函数,其本质都是通过创建 Vector ,然后向其添加输入流(并将值赋给成员变量 e)来实现的。而且两个方法都调用了 nextStream( ) 这个方法。

final void nextStream() throws IOException {

    // 不为空,关闭流。说明当前输入流已读取完毕准备下一个输入流的读取
    // 不明白可以先往下看
    if (in != null) {
        in.close();
    }

    //注意 -->是 if 不是 while
    if (e.hasMoreElements()) {

        //获取下一个输入流
        in = (InputStream) e.nextElement();
        if (in == null) {
            throw new NullPointerException();
        }
    } else {
        in = null;
    }

}

观察代码大概能知道了它的用处是关闭当前输入流(说明我们在代码中可以省略输入流的关闭流操作),并获取下一个输入流。


read 方法,这里定义 2 种读取方式。

public int read() throws IOException {
    // 表示 vector 中的输入流已经全部读取完了
    if (in == null) {
        return -1;
    }

    int c = in.read();

    //读取完输入流,进行递归操作
    if (c == -1) {
        // 关闭当前输入流,并获取下一个输入流
        nextStream();
        return read();
    }
    return c;
}

public int read(byte b[], int off, int len) throws IOException {
    // 判断参数的合法性
    if (in == null) {
        return -1;
    } else 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 n = in.read(b, off, len);

    if (n <= 0) {
        nextStream();
        return read(b, off, len);
    }

    return n;
}

观察代码可以知道 read 方法会依次读取当前的所有输入流,每当读取完一个输入流,就会调用 nextStream 方法获取下一个输入流,然后进行递归返回到 read 方法。直到所有的输入流被读取完后,返回 -1 结束。


剩余方法

//available 方法
public int available() throws IOException {
    if (in == null) {
        return 0; // no way to signal EOF from available()
    }
    return in.available();
}

//close 方法
public void close() throws IOException {
    do {
        nextStream();
    } while (in != null);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oxf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值