如何将多个不同的InputStream链接到一个InputStream中

问题描述 投票:55回答:5

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

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

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

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

java scala io inputstream
5个回答
92
投票

它就在JDK中!引用JavaDoc of SequenceInputStream

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

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

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

......你明白了。

See also


13
投票

这是使用SequencedInputStream完成的,这在Java中是直截了当的,正如Tomasz Nurkiewicz的答案所示。我最近不得不在一个项目中反复这样做,所以我通过“pimp my library”模式添加了一些Scala-y善良。

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(_++_)

10
投票

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

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)))

1
投票

这是一个使用Vector的更优雅的解决方案,这是专门为Android而使用任何Java的矢量

    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

0
投票

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

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

def concatInputStreams(streams: Iterator[InputStream]): InputStream =
  new SequenceInputStream(streams.asJavaEnumeration)
© www.soinside.com 2019 - 2024. All rights reserved.