Java IO: SequenceInputStream 类

在 Java 中,SequenceInputStream 可以将两个或多个其他 InputStream 流合二为一。首先,SequenceInputStream 会读取第一个 InputStream 流中的所有字节,然后读取第二个 InputStream 流中的所有字节。这就是它被称为 SequenceInputStream 的原因,因为 InputStream 实例是按顺序读取的。如下图:

image.png

SequenceInputStream 示例

现在我们来看一个如何使用 SequenceInputStream 的示例。下面是一个简单的 Java SequenceInputStream 示例,该示例通过 ByteArrayInputStream 创建了两个输入流 input1 和 input2,如下:

package com.hxstrive.java_io;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;

public class SequenceInputStreamExample {

    public static void main(String[] args) throws IOException {
        // 定义两个输入流
        InputStream input1 = new ByteArrayInputStream("hello".getBytes());
        InputStream input2 = new ByteArrayInputStream(" world".getBytes());

        // 使用 SequenceInputStream 将两个输入流合并
        try(SequenceInputStream inputStream = new SequenceInputStream(input1, input2)) {
            int value = -1;
            while((value = inputStream.read()) != -1) {
                System.out.print((char)value);
            }
            System.out.println("\n");
        }
    }

}
// 输出:hello world

上述代码,首先创建了两个 ByteArrayInputStream 实例,ByteArrayInputStream 类也继承了 InputStream 类,因此它们可以与 SequenceInputStream 一起使用。

其次,创建了一个 SequenceInputStream 实例。SequenceInputStream 将两个 ByteArrayInputStream 实例作为构造函数参数。这就告诉 SequenceInputStream 结合两个 InputStream 实例的方法。

现在,与 SequenceInputStream 结合在一起的两个 InputStream 实例可以像一个连贯的流一样使用。当没有更多数据可从第二个 InputStream 中读取时,SequenceInputStream read() 方法将像其他 InputStream 一样返回-1。

合并两个以上的 InputStream

可以通过两种方式将两个以上的 InputStream 实例与 SequenceInputStream 结合起来。

方式一:使用 Vector

将所有 InputStream 实例放入一个 Vector 中,然后将该 Vector 传递给 SequenceInputStream 构造函数。如下:

package com.hxstrive.java_io;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.util.Vector;

public class SequenceInputStreamExample2 {

    public static void main(String[] args) throws IOException {
        // 定义两个输入流
        InputStream input1 = new ByteArrayInputStream("one".getBytes());
        InputStream input2 = new ByteArrayInputStream(" two".getBytes());
        InputStream input3 = new ByteArrayInputStream(" three".getBytes());

        // 将输入流放入 Vector 中
        Vector<InputStream> vector = new Vector<>();
        vector.add(input1);
        vector.add(input2);
        vector.add(input3);

        // 使用 SequenceInputStream 将两个输入流合并
        try(SequenceInputStream inputStream = new SequenceInputStream(vector.elements())) {
            int value = -1;
            while((value = inputStream.read()) != -1) {
                System.out.print((char)value);
            }
            System.out.println("\n");
        }
    }

}
// 输出:one two three

方法二:SequenceInputStream 与 SequenceInputStream 结合

将两个和两个 InputStream 实例合并为 SequenceInputStream 实例,然后再将这些实例与另一个 SequenceInputStream 实例合并。以下是将两个以上的 InputStream 实例与多个 SequenceInputStream 实例组合起来的效果:

package com.hxstrive.java_io;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;

public class SequenceInputStreamExample3 {

    public static void main(String[] args) throws IOException {
        // 定义两个输入流
        InputStream input1 = new ByteArrayInputStream("one".getBytes());
        InputStream input2 = new ByteArrayInputStream(" two".getBytes());
        InputStream input3 = new ByteArrayInputStream(" three".getBytes());
        InputStream input4 = new ByteArrayInputStream(" four".getBytes());

        // 组合两个中间 SequenceInputStream
        SequenceInputStream sequence1 = new SequenceInputStream(input1, input2);
        SequenceInputStream sequence2 = new SequenceInputStream(input3, input4);

        // 使用 SequenceInputStream 将两个输入流合并
        try(SequenceInputStream inputStream = new SequenceInputStream(sequence1, sequence2)) {
            int value = -1;
            while((value = inputStream.read()) != -1) {
                System.out.print((char)value);
            }
            System.out.println("\n");
        }
    }

}
// 结果:one two three four

上面示例,最终生成的对象图如下图:

image.png

关闭 SequenceInputStream

完成从 SequenceInputStream 读取数据后,必须记得关闭 SequenceInputStream。关闭 SequenceInputStream 也会关闭 SequenceInputStream 正在读取的 InputStream 实例,也就是说,如果一个 SequenceInputStream 关联了两个 InputStream,如果 SequenceInputStream  被关闭了,那么它关联的 InputStream 也会自动关闭

下面是部分源码:

public void close() throws IOException {
    // 循环调用 nextStream() 关闭流,知道 in 为 null,即没有流为止
    do {
        nextStream();
    } while (in != null);
}

final void nextStream() throws IOException {
    if (in != null) {
        in.close(); // 关闭流
    }

    // 判断是否还有下一个流,如果有,赋值给 in 变量
    if (e.hasMoreElements()) {
        in = (InputStream) e.nextElement();
        if (in == null)
            throw new NullPointerException();
    }
    else in = null;

}

注意,关闭 SequenceInputStream 需要调用其 close() 方法。如下:

sequenceInputStream.close();

当然,你还可以使用 Java 7 中引入的 try-with-resources 结构。如下:

InputStream input1 = new FileInputStream("d:\\file1.txt");
InputStream input2 = new FileInputStream("d:\\file2.txt");

try(SequenceInputStream sequenceInputStream = new SequenceInputStream(input1, input2)){
    int data = sequenceInputStream.read();
    while(data != -1){
        System.out.println(data);
        data = sequenceInputStream.read();
    }
}

请注意,这里不再有任何明确的 close() 方法调用,全权由 try-with-resources 负责去调用 close() 方法关闭流。

📢特别注意:上述实例中,两个 FileInputStream 实例并没有在 try-with-resources 代码块中创建。这意味着 try-with-resources 块不会自动关闭这两个 FileInputStream 实例。不过,当 SequenceInputStream 关闭时,它也会关闭其关联的 InputStream 实例,因此当 SequenceInputStream 关闭时,这两个 FileInputStream 实例也会被关闭。

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号