programing

OutputStream에서 InputStream을 생성하는 가장 효율적인 방법

yoursource 2022. 10. 3. 22:43
반응형

OutputStream에서 InputStream을 생성하는 가장 효율적인 방법

다음 페이지: http://blog.ostermiller.org/convert-java-outputstream-inputstream에서는 OutputStream에서 InputStream을 작성하는 방법에 대해 설명합니다.

new ByteArrayInputStream(out.toByteArray())

다른 대안으로는 번거로운 PipedStreams 및 새 스레드를 사용하는 방법이 있습니다.

메모리 바이트 배열에 새로운 메가바이트를 복사하는 것은 마음에 들지 않습니다.이것을 보다 효율적으로 할 수 있는 도서관이 있나요?

편집:

Laurence Gonsalves의 조언에 따라 Piped Streams에 도전해 봤는데, 그렇게 다루기 어렵지 않다는 것을 알게 되었습니다.다음은 clojure 샘플 코드입니다.

(defn #^PipedInputStream create-pdf-stream [pdf-info]
  (let [in-stream (new PipedInputStream)
        out-stream (PipedOutputStream. in-stream)]
    (.start (Thread. #(;Here you write into out-stream)))
    in-stream))

모든 데이터를 메모리 내 버퍼에 한꺼번에 복사하지 않으려면 OutputStream(프로듀서)을 사용하는 코드와 InputStream(컨슈머)을 사용하는 코드를 같은 스레드에서 번갈아 사용하거나 두 개의 개별 스레드에서 동시에 작동해야 합니다.같은 스레드로 동작시키는 것은 아마도 2개의 개별 스레드를 사용하는 것보다 훨씬 더 복잡할 수 있습니다.또, 전기 소비 장치가 입력을 기다리는 것을 차단하지 않도록 할 필요가 있습니다.그렇지 않으면, 생산자와 전기 소비자는 같은 루프로 동작할 필요가 있습니다.이것은 너무 긴밀해 보이는 것입니다.위로 올렸다.

두 번째 실을 쓰세요.그렇게 복잡하지 않아요.링크한 페이지에는 적절한 예가 있습니다.다음은 스트림을 닫는 다소 현대화된 버전입니다.

try (PipedInputStream in = new PipedInputStream()) {
    new Thread(() -> {
        try (PipedOutputStream out = new PipedOutputStream(in)) {
            writeDataToOutputStream(out);
        } catch (IOException iox) {
            // handle IOExceptions
        }
    }).start();
    processDataFromInputStream(in);
}

파이프와 스레드를 투명하게 처리하는 EasyStream이라는 다른 오픈 소스 라이브러리가 있습니다.모든 것이 잘 되면 그것은 그다지 복잡하지 않다.문제가 발생하는 것은 (Laurence Gonsalves의 예를 참조해 주세요.

class1.putDataOnOutputStream(out);

예외를 슬로우합니다.이 예에서는 스레드가 단순히 완료되고 예외가 손실되며 외부는InputStream잘릴 수 있습니다.

Easystream은 예외 전파 및 제가 약 1년 동안 디버깅한 기타 귀찮은 문제에 대처하고 있습니다.(저는 라이브러리의 창안자입니다.솔루션이 최선입니다.)다음은 사용 방법의 예입니다.

final InputStreamFromOutputStream<String> isos = new InputStreamFromOutputStream<String>(){
 @Override
 public String produce(final OutputStream dataSink) throws Exception {
   /*
    * call your application function who produces the data here
    * WARNING: we're in another thread here, so this method shouldn't 
    * write any class field or make assumptions on the state of the outer class. 
    */
   return produceMydata(dataSink)
 }
};

또한 OutputStream을 InputStream으로 변환하는 다른 모든 방법에 대해서도 설명합니다.볼만해.

한 목적의 버퍼 복사를 입니다.ByteArrayOutputStream:

public class CopyStream extends ByteArrayOutputStream {
    public CopyStream(int size) { super(size); }

    /**
     * Get an input stream based on the contents of this output stream.
     * Do not use the output stream after calling this method.
     * @return an {@link InputStream}
     */
    public InputStream toInputStream() {
        return new ByteArrayInputStream(this.buf, 0, this.count);
    }
}

따라서 스트림에 해, 「 」, 「 」, 「 」, 「 」를 합니다.toInputStream기본 버퍼를 통해 입력 스트림을 가져옵니다.출력 스트림은 그 시점 이후에 닫힌 것으로 간주합니다.

InputStream을 OutputStream에 연결하는 가장 좋은 방법은 파이핑된 스트림을 사용하는 것이라고 생각합니다.이 스트림은 java.io 패키지로 다음과 같이 제공됩니다.

// 1- Define stream buffer
private static final int PIPE_BUFFER = 2048;

// 2 -Create PipedInputStream with the buffer
public PipedInputStream inPipe = new PipedInputStream(PIPE_BUFFER);

// 3 -Create PipedOutputStream and bound it to the PipedInputStream object
public PipedOutputStream outPipe = new PipedOutputStream(inPipe);

// 4- PipedOutputStream is an OutputStream, So you can write data to it
// in any way suitable to your data. for example:
while (Condition) {
     outPipe.write(mByte);
}

/*Congratulations:D. Step 4 will write data to the PipedOutputStream
which is bound to the PipedInputStream so after filling the buffer
this data is available in the inPipe Object. Start reading it to
clear the buffer to be filled again by the PipedInputStream object.*/

내 생각에 이 코드에는 두 가지 주요 이점이 있습니다.

1 - 버퍼 이외의 메모리 소비는 없습니다.

2 - 데이터 큐잉을 수동으로 처리할 필요가 없습니다.

교착 상태가 될 가능성이 높아지고, 코드를 이해하기 어렵고, 예외에 대처하는 문제가 있기 때문에, 저는 보통 스레드를 따로 만드는 것을 피하려고 합니다.

다음은 제가 제안하는 솔루션입니다.ProducerInputStream은 productChunk()에 대한 반복 호출을 통해 콘텐츠를 청크로 만듭니다.

public abstract class ProducerInputStream extends InputStream {

    private ByteArrayInputStream bin = new ByteArrayInputStream(new byte[0]);
    private ByteArrayOutputStream bout = new ByteArrayOutputStream();

    @Override
    public int read() throws IOException {
        int result = bin.read();
        while ((result == -1) && newChunk()) {
            result = bin.read();
        }
        return result;
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        int result = bin.read(b, off, len);
        while ((result == -1) && newChunk()) {
            result = bin.read(b, off, len);
        }
        return result;
    }

    private boolean newChunk() {
        bout.reset();
        produceChunk(bout);
        bin = new ByteArrayInputStream(bout.toByteArray());
        return (bout.size() > 0);
    }

    public abstract void produceChunk(OutputStream out);

}

언급URL : https://stackoverflow.com/questions/1225909/most-efficient-way-to-create-inputstream-from-outputstream

반응형