M12i.

学術書・マンガ・アニメ・映画の消費活動とプログラミングについて

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がクラッシュする可能性もあると思います。したがって閾値をどこらに置くかは要検討であるとしても、バイト配列が一定の長さに達したときに、一時ファイルを書き出すようにする工夫が必要だと思います。例えばこんな感じです。