Java IO 之 SequenceInputStream 原理解析

概述

今天给大家分享一个比较有意思的 IO 流。SequenceInputStream ,听名字顾名思义。

SequenceInputStream 流可以把多个 InputStream 合并为一个 InputStream . 按照指定的顺序,把几个输入流连续地合并起来,使用起来像一个流一样。并且使它们像单个输入流一样出现。每个输入流依次被读取,直到到达该流的末尾。然后“序列输入流”类关闭这个流并自动地切换到下一个输入流。

合并流的作用是将多个源合并合一个源。

使用场景

比如现在有三个文件【1.txt】、【2.txt】、【3.txt】;现在要把这三个文件按照1、2、3的顺序合并成一个文件输出到 【all.txt】文件中。

如果不知道有这个流,大家可能都是自己一个一个文件的去读,自己合并到一个文件中。 有了这个流,我们操作起来,代码更加优雅。

示例

public class SequenceInputStreamDemo {
    public static void sequenceStream() {
        // 创建字节输入流对象s1,s2,s3
        try (InputStream s1 = new FileInputStream(new File("d:\\1.txt"));
                InputStream s2 = new FileInputStream(new File("d:\\2.txt"));
                InputStream s3 = new FileInputStream(new File("d:\\3.txt"));) {

            /**
             * SequenceInputStream(Enumeration<? extends InputStream> e)
             * 通过记住参数来初始化新创建的 SequenceInputStream, 该参数必须是生成运行时类型为 InputStream
             * 对象的 Enumeration 型参数。
             */
            // 创建一个Vector类对象v
            Vector<InputStream> v = new Vector<>();
            /**
             * void addElement(E obj) 将指定的组件添加到此向量的末尾,将其大小增加 1。
             */
            // 将3个字节流对象添加到Vector容器中
            v.addElement(s1);
            v.addElement(s2);
            v.addElement(s3);
            // 获取Vector对象中的元素
            Enumeration<InputStream> e = v.elements();
            // 将Enumeration对象中的流合并(创建一个序列流,用于合并多个字节流文件s1,s2,s3)
            try (SequenceInputStream se = new SequenceInputStream(e);
                    OutputStream os = new FileOutputStream("d:\\all.txt")) {
                byte[] b = new byte[1024];
                int len = 0;
                while ((len = se.read(b)) != -1) {
                    os.write(b, 0, len);
                    os.write("\r\n".getBytes());
                }
                System.out.println("合并成功");
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        sequenceStream();
    }
}

该示例是,把D盘目录下的三个文件【1.txt】、【2.txt】、【3.txt】使用SequenceInputStream 流,按照 指定的文件的顺序合并输出到 【all.txt】 文件中。

SequenceInputStream 源码解析

public class SequenceInputStream extends InputStream {
    Enumeration<? extends InputStream> e;
    InputStream in;
    ......
}

SequenceInputStream 继承 InputStream。 定义了一个 Enumeration 的一个变量。该变量存储的是所有需要合并的InputStream。 定义了一个 InputStream的一个变量。该变量是记录 Enumeration 中正在读去的 InputStream。

Enumeration Enumeration 接口是Iterator迭代器的“古老版本”,从JDK 1.0开始,Enumeration接口就已经存在了(Iterator从JDK 1.2才出现)。Enumeration接口只有两个方法。

构造方法

提供两个构造方法。

  • 1、提供 Enumeration 类型的参数。 把传过来的参数赋值给 e 变量。 并调用 nextStream() 方法。

现在的迭代器都在使用Iterator,而这里为啥还在使用Enumeration 呢? 因为 Iterator 是在JDK1.2以后才有的,而SequenceInputStream 这个流在JDK1.0就已经存在了,故使用 Enumeration 当参数。

  • 2、提供两个 InputStream 类型的参数。 构造中把这两个流添加到 Vector 数组中,然后调用 elements 方法放回一个 Enumeration 类型,并赋值给 e 变量。 并调用 nextStream() 方法。

nextStream 方法

1、判断该流是否不为null,不为null 则把当前 InputStream 关闭。 2、该方法是先判断 Enumeration 中是否有可用的元素,如果获取 Enumeration 迭代器中下一个的元素,并赋值给 in 变量。

read 方法

读取 InputStream 中的数据。如果当前 InputStream 读取完了,再调用 nextStream 方法,获取下一个流,然后继续读取。直到所有的流都已经读取完毕。

close 方法

close 方法会关闭剩下没有读取完的所有的 InputStream。 读取过的InputStream 会在 调用 nextStream 方法中关闭。所以在这只需要关闭没有读取完的流就可以了。

看完源码是不是感觉 SequenceInputStream 超级简单,自己也可以实现一个。


本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大闲人柴毛毛

深入理解java异常处理机制

 1. 引子        try…catch…finally恐怕是大家再熟悉不过的语句了,而且感觉用起来也是很简单,逻辑上似乎也是很容易理解。不过,...

2394
来自专栏java学习

Java每日一练(2017/8/21)

每日一句 学的到东西的事情是锻炼,学不到的是磨练。 查看以前的所有练习题目以及答案:https://mp.weixin.qq.com/mp/homepage?_...

35416
来自专栏DannyHoo的专栏

Block

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010105969/article/details/...

1202
来自专栏吾爱乐享

java学习之数组元素排序,冒泡排序和选择排序

1164
来自专栏大闲人柴毛毛

稳扎稳打JavaScript(一)——作用域链内存模型

几个概念 在开始之前,先了解几个概念。 1.1. 作用域 作用域是指当前正在执行的代码能够访问到变量的范围; 每个函数都有各自的作用域,存储函数所有的局部变量...

4618
来自专栏noteless

[十五]javaIO之SequenceInputStream

SequenceInputStream的使用比较简单,只需要传递进入两个流或者一个包含流的Enumeration即可

1231
来自专栏全沾开发(huā)

搞懂JavaScript中的连续赋值

搞懂JavaScript中的连续赋值 前段时间老是被一道题刷屏,一个关于连续赋值的坑。 遂留下一个笔记,以后再碰到有人问这个题,直接...

3936
来自专栏Java帮帮-微信公众号-技术文章全总结

Java企业面试——Java基础

1. Java基础部分 1.1 Java中的方法覆盖(Overwrite)和方法重载(Overloading)是什么意思? 重载Overload表示同一个类中...

2784
来自专栏云霄雨霁

Java--泛型的约束和局限性

1554
来自专栏AI研习社

最常见的 35 个 Python 面试题及答案(2018 版)

作为一个 Python 新手,你必须熟悉基础知识。在本文中我们将讨论一些 Python 面试的基础问题和高级问题以及答案,以帮助你完成面试。包括 Python ...

7293

扫码关注云+社区

领取腾讯云代金券