91

このページ:http://blog.ostermiller.org/convert-java-outputstream-inputstream は、OutputStreamからInputStreamを作成する方法を説明しています。

new ByteArrayInputStream(out.toByteArray())

他の選択肢は、面倒なPipedStreamsと新しいスレッドを使用することです。

多くのメガバイトを新しいメモリバイト配列にコピーするというアイデアは好きではありません。これをより効率的に行うライブラリはありますか?

編集:

Laurence Gonsalvesからのアドバイスにより、PipedStreamsを試してみましたが、それほど難しくはないことがわかりました。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))
4

5 に答える 5

77

一度にすべてのデータをメモリ内バッファにコピーしたくない場合は、OutputStream を使用するコード (プロデューサー) と InputStream を使用するコード (コンシューマー) が必要になります。 ) 同じスレッドで交互に実行するか、2 つの別々のスレッドで同時に操作します。それらを同じスレッドで動作させることは、2 つの別々のスレッドを使用することよりもおそらくはるかに複雑であり、はるかにエラーが発生しやすく (コンシューマーが入力の待機を決してブロックしないようにする必要があります。そうしないと、実質的にデッドロックになります)、必要になります。プロデューサーとコンシューマーが同じループで実行されているため、緊密に結合されているように見えます。

したがって、2 番目のスレッドを使用します。それほど複雑ではありません。リンク先のページには合理的な例がありました。これはやや近代化されたバージョンで、ストリームも閉じます。

try (PipedInputStream in = new PipedInputStream()) {
    new Thread(() -> {
        try (PipedOutputStream out = new PipedOutputStream(in)) {
            writeDataToOutputStream(out);
        } catch (IOException iox) {
            // handle IOExceptions
        }
    }).start();
    processDataFromInputStream(in);
}
于 2009-08-04T07:06:25.453 に答える
14

透過的な方法でパイプとスレッドを処理するEasyStreamと呼ばれる別のオープン ソース ライブラリがあります。すべてがうまくいけば、それはそれほど複雑ではありません。問題が発生する場合 (Laurence Gonsalves の例を参照)

class1.putDataOnOutputStream(アウト);

例外をスローします。その例では、スレッドは単純に完了し、例外は失われますが、外側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 に変換する他のすべての方法が説明されている優れた紹介もあります。一見の価値があります。

于 2011-06-02T11:30:32.643 に答える
11

バッファのコピーを回避する簡単な解決策は、特別な目的の を作成すること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て基になるバッファーを介して入力ストリームを取得します。その時点以降、出力ストリームは閉じていると考えてください。

于 2016-05-01T00:25:20.377 に答える
7

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.*/

私の意見では、このコードには 2 つの主な利点があります。

1 - バッファを除いて追加のメモリ消費はありません。

2 - データ キューイングを手動で処理する必要がない

于 2015-01-28T12:11:39.293 に答える