65

我想知道是否有任何理想的方式可以将多个 InputStreams 链接到 Java(或 Scala)中的一个连续 InputStream 中。

我需要它来解析我从 FTP 服务器通过网络加载的平面文件。我想要做的是获取文件 [1..N],打开流,然后将它们组合成一个流。所以当file1结束时,我想从file2开始读取,依此类推,直到到达fileN的末尾。

我需要以特定顺序读取这些文件,数据来自一个遗留系统,该系统在 barches 中生成文件,因此一个中的数据依赖于另一个文件中的数据,但我想将它们作为一个连续流处理以简化我的域逻辑接口.

我四处搜索并找到了 PipedInputStream,但我并不肯定这就是我所需要的。一个例子会很有帮助。

4

5 回答 5

106

它就在JDK中!引用JavaDoc 的SequenceInputStream

ASequenceInputStream表示其他输入流的逻辑串联。它从输入流的有序集合开始,从第一个读取直到到达文件末尾,然后从第二个读取,依此类推,直到最后一个包含的输入流到达文件末尾。

您想连接任意数量的InputStreams 而SequenceInputStream只​​接受两个。但是由于SequenceInputStream也是一个,InputStream您可以递归地应用它(嵌套它们):

new SequenceInputStream(
    new SequenceInputStream(
        new SequenceInputStream(file1, file2),
        file3
    ),
    file4
);

...你明白了。

也可以看看

于 2013-01-12T16:08:04.670 回答
16

这是使用 SequencedInputStream 完成的,这在 Java 中很简单,正如 Tomasz Nurkiewicz 的回答所示。最近我不得不在一个项目中重复这样做,所以我通过“pimp my library”模式添加了一些 Scala 的优点。

object StreamUtils {
  implicit def toRichInputStream(str: InputStream) = new RichInputStream(str)

  class RichInputStream(str: InputStream) {
// a bunch of other handy Stream functionality, deleted

    def ++(str2: InputStream): InputStream = new SequenceInputStream(str, str2)
  }
}

有了它,我可以按如下方式进行流排序

val mergedStream = stream1++stream2++stream3

甚至

val streamList = //some arbitrary-length list of streams, non-empty
val mergedStream = streamList.reduceLeft(_++_)
于 2013-01-12T16:34:38.220 回答
15

另一种解决方案:首先创建输入流列表,然后创建输入流序列:

List<InputStream> iss = Files.list(Paths.get("/your/path"))
        .filter(Files::isRegularFile)
        .map(f -> {
            try {
                return new FileInputStream(f.toString());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }).collect(Collectors.toList());

new SequenceInputStream(Collections.enumeration(iss)))
于 2016-07-15T15:13:15.670 回答
1

这是一个使用 Vector 的更优雅的解决方案,这专门针对 Android,但对任何 Java 都使用 vector

    AssetManager am = getAssets();
    Vector v = new Vector(Constant.PAGES);
    for (int i =  0; i < Constant.PAGES; i++) {
        String fileName = "file" + i + ".txt";
         InputStream is = am.open(fileName);
         v.add(is);
    }
    Enumeration e = v.elements();
    SequenceInputStream sis = new SequenceInputStream(e);
    InputStreamReader isr = new InputStreamReader(sis);

    Scanner scanner = new Scanner(isr);   // or use bufferedReader
于 2013-09-24T10:04:08.327 回答
0

这是一个简单的 Scala 版本,它连接了一个Iterator[InputStream]:

import java.io.{InputStream, SequenceInputStream}
import scala.collection.JavaConverters._

def concatInputStreams(streams: Iterator[InputStream]): InputStream =
  new SequenceInputStream(streams.asJavaEnumeration)
于 2018-06-13T09:30:40.260 回答