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