C++でpopenで開いたプロセスをistreamから読む

C++でpopenで開いたプロセスをistreamから読み込む方法でかなり手こずったのでメモ

圧縮ファイルをgunzipなどで解凍してから受け取りたい場合など,他のプロセスの実効結果を受け取りたいたいことが多々あります

Cでは,fopenもpopenもFILE構造体へのポインタを返すので,開かれたものがファイルだったかプロセスだったのかを気にすること無くFILE構造体へのポインタを後の処理に使うことができました

C++では,fprintfやfscanfといった従来の入出力の代わりにiostreamを用いて似たようなことができますが,プロセスを扱うための標準ライブラリはg++にはないようでした(boostや外部のライブラリには存在するようですが,iostreamから統一的にアクセスする方法は良く分かりませんでした・・)

古いg++では,ifstreamのコンストラクタにファイル記述子を与えてやることでCのfopenやpopenが返すFILEポインタからistreamを構築することが可能でしたが,最近のg++ではこの仕様は標準ではなくなってしまったようです

今のg++で上記のことを実現するためには以下の様に__gnu_cxx::stdio_filebufを使ってstreambufを作成し,istreamのコンストラクタに渡してやります

#include <ext/stdio_filebuf.h>

string command = "gunzip -c " + file;
FILE *fp = popen(command.c_str(), "r");
__gnu_cxx::stdio_filebuf<char> *p_fb = new __gnu_cxx::stdio_filebuf<char>(fp, ios_base::in);
in = new istream((streambuf *)p_fb);

応用すれば色々できそうだ