InputStreamを生成するOutputStreamを生成する
ちょっとふざけたようなタイトルですが今回はJavaについてのメモです。
やりたいことは、何かしらの処理──例えばDOMのAPIを通じて作成したXMLデータや、テンプレートエンジンがレンダリングしたものをストリームに書き出すとか──の結果を、そっくりそのまま入力データとして受け取って後続の処理で活用したい、ということです。
Javaで言えば「OutputStreamからInputStreamをつくりたい」というかむしろ「InputStreamを生成するOutputStreamをつくりたい」ということになります。
実現にはこちらのページもヒントになりましたが(でも正直よく分からなかった)、とにかくコードにしてみれば実に簡単です:
/** * 入力ストリームを生成する出力ストリーム. * 出力ストリームとして何かしらの処理の結果を受け取り内部的に貯めこんで、 * その結果をもとにして入力ストリームを生成する。 */ public final class PipeOutputStream extends OutputStream { /** * データを貯めこむバイト配列ストリーム. */ private final ByteArrayOutputStream inner = new ByteArrayOutputStream(); @Override public void write(final int b) throws IOException { inner.write(b); } /** * 入力ストリームを生成して返す. * @return 入力ストリーム */ public InputStream getInputStream() { return new ByteArrayInputStream(inner.toByteArray()); } }
頭が情報工学系でないので、まずまっさきに「OutputStreamからInputStreamをつくりたい」(前述)と考えてしまって無駄に悩んでしまったのですが、「InputStreamを生成するOutputStreamをつくりたい」が正解で、そう考えればどうということもなしです。
(2015/05/06追記)ちょっとした出力内容であればこれでも問題ないのですが、例えば外部コマンドが出力する内容が数MB以上になる場合、上記のような実装ではOutOfMemory例外が発生してJVMがクラッシュする可能性もあると思います。したがって閾値をどこらに置くかは要検討であるとしても、バイト配列が一定の長さに達したときに、一時ファイルを書き出すようにする工夫が必要だと思います。例えばこんな感じです。