Program Club

여러 개의 다른 InputStream을 하나의 InputStream으로 연결하는 방법

proclub 2020. 12. 15. 19:31
반응형

여러 개의 다른 InputStream을 하나의 InputStream으로 연결하는 방법


Java (또는 Scala)에서 여러 InputStream을 하나의 연속적인 InputStream으로 연결하는 이데올로기적인 방법이 있는지 궁금합니다.

내가 필요한 것은 FTP 서버에서 네트워크를 통해로드하는 플랫 파일을 구문 분석하는 것입니다. 내가하고 싶은 것은 파일 [1..N]을 가져 와서 스트림을 연 다음 하나의 스트림으로 결합하는 것입니다. 따라서 file1이 끝날 때 fileN의 끝에 도달 할 때까지 file2 등에서 읽기를 시작하고 싶습니다.

이 파일을 특정 순서로 읽어야합니다. 데이터는 바치 형식의 파일을 생성하는 레거시 시스템에서 가져 오므로 한 데이터는 다른 파일의 데이터에 의존하지만 도메인 논리 인터페이스를 단순화하기 위해 하나의 연속 스트림으로 처리하고 싶습니다. .

나는 주변을 수색하고 PipedInputStream을 찾았지만 그것이 내가 필요로하는 것이 확실하지 않습니다. 예가 도움이 될 것입니다.


JDK에 바로 있습니다! JavaDocSequenceInputStream 인용 :

A SequenceInputStream는 다른 입력 스트림의 논리적 연결을 나타냅니다. 순서가 지정된 입력 스트림 모음으로 시작하여 파일의 끝에 도달 할 때까지 첫 번째부터 읽습니다. 그런 다음 포함 된 입력 스트림의 마지막에 파일의 끝에 도달 할 때까지 두 번째부터 읽습니다.

2 개만 허용 InputStream하면서 임의의 수를 연결하려고합니다 SequenceInputStream. 하지만 이후 SequenceInputStream도 인은 InputStream재귀 (둥지를) 적용 할 수 있습니다 :

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

... 당신은 아이디어를 얻습니다.

또한보십시오


이것은 Tomasz Nurkiewicz의 답변에서 알 수 있듯이 Java에서 간단한 SequencedInputStream을 사용하여 수행됩니다. 최근 프로젝트에서이 작업을 반복해야했기 때문에 "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(_++_)

또 다른 해결책 : 먼저 입력 스트림 목록을 만든 다음 입력 스트림 시퀀스를 만듭니다.

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

여기에 벡터를 사용하는보다 우아한 솔루션이 있습니다. 이것은 특히 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

다음은 다음을 연결하는 간단한 Scala 버전입니다 Iterator[InputStream].

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

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

참조 URL : https://stackoverflow.com/questions/14295099/how-to-chain-multiple-different-inputstreams-into-one-inputstream

반응형