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

时间:2013-01-12 16:02:24

标签: java scala io inputstream

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

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

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

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

5 个答案:

答案 0 :(得分:92)

它就在JDK中!引用JavaDoc of SequenceInputStream

  

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

您希望连接任意数量的InputStream,而SequenceInputStream只接受两个SequenceInputStream。但由于InputStream也是new SequenceInputStream( new SequenceInputStream( new SequenceInputStream(file1, file2), file3 ), file4 ); ,你可以递归地应用它(嵌套它们):

{{1}}

......你明白了。

另见

答案 1 :(得分:14)

这是使用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(_++_)

答案 2 :(得分: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)))

答案 3 :(得分: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

答案 4 :(得分:0)

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

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

def concatInputStreams(streams: Iterator[InputStream]): InputStream =
  new SequenceInputStream(streams.asJavaEnumeration)