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

现在我们来看一个如何使用 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 实例与 SequenceInputStream 结合起来。
将所有 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将两个和两个 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上面示例,最终生成的对象图如下图:

完成从 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 实例也会被关闭。