web-dev-qa-db-ja.com

OutputStreamからInputStreamを作成する最も効率的な方法

このページ: 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))
79
Vagif Verdi

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

したがって、2番目のスレッドを使用します。それほど複雑ではありません。あなたがリンクしたページには完璧な例がありました:

  PipedInputStream in = new PipedInputStream();
  PipedOutputStream out = new PipedOutputStream(in);
  new Thread(
    new Runnable(){
      public void run(){
        class1.putDataOnOutputStream(out);
      }
    }
  ).start();
  class2.processDataFromInputStream(in);
67

パイプとスレッドを透過的に処理するEasyStreamという別のオープンソースライブラリがあります。すべてがうまくいけば、それは本当に複雑ではありません。問題が発生する場合(ローレンスゴンサルベスの例を見て)

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

Nice introduction もあり、OutputStreamをInputStreamに変換する他のすべての方法が説明されています。見る価値がある。

15
Gab

バッファのコピーを避ける簡単な解決策は、特別な目的の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を呼び出して、基礎となるバッファで入力ストリームを取得します。そのポイントの後に出力ストリームが閉じていると考えてください。

9
Eron Wright

InputStreamをOutputStreamに接続する最良の方法は、次のように--.piped streams-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-データのキューイングを手動で処理する必要はありません

6

私は通常、デッドロックの可能性の増加、コードの理解の難しさ、および例外を処理する問題のために、別個のスレッドの作成を避けようとします。

私が提案するソリューションは次のとおりです。produceChunk()を繰り返し呼び出すことにより、チャンクでコンテンツを作成するProducerInputStream:

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

}
1
Mark