Boost.IostreamsのFilterを使う!
Boost.IostreamsにはFilterというものがあります。
これを使うことでストリームから入力、ストリームへ出力するデータを加工できます。
#include <iostream> #include <boost/iostreams/filtering_stream.hpp> #include <boost/iostreams/filter/gzip.hpp> #include <boost/iostreams/device/file_descriptor.hpp> int main(){ namespace io = boost::iostreams; //データをgzip圧縮してファイルに書き出し io::filtering_ostream out; out.push(io::gzip_compressor()); out.push(io::file_descriptor_sink("gzip_file.gz")); out << "Example characters"; io::close(out); //データをflush //ファイルからデータを読み込んでgzip展開 io::filtering_istream in; in.push(io::gzip_decompressor()); in.push(io::file_descriptor_source("gzip_file.gz")); std::string str; in >> str; std::cout << str << std::endl; return 0; }
Output:
Example
"Example characters"と出力されそうな気がしますが、これは>>演算子を使ったため、std::cinと同じようにスペースを区切りとして出力されました。
ひとまず、これはおいておきます。
上記のコードでは、まずfiltering_ostreamに、DualUseFilter*1であるgzip_compressorをpushしました。
そしてファイルへ出力するSinkであるfile_descriptor_sinkをpushしました。
これで、データを出力するとき、データはgzip_compressorを通って圧縮され、file_descriptor_sinkに流れてファイルに出力されます。
filtering_ostreamでは、データはFilterを通ってSinkへと、pushした順番に流れていきます。
次に、filtering_istreamに、DualUseFilterのgzip_decompressorを、そしてSourceのfile_descriptor_sourceをpushしました。
file_descriptor_sourceでファイルからデータが読み込まれ、gzip_decompressorで展開されて、変数に入力されます。
filtering_istreamでは、pushしたFilterからSourceとは逆の順番で、データが流れていきます。
SinkもSourceも、必ず一番最後にpushします。これがデータの流れ着く先、湧き出る元となるので。
ここではFilterはひとつだけ使いました。Filterは0個以上使える、ということになっています。
つまりFilterを何も使わず、Deviceのみをpushし、io::filtering_streamをio::streamと同じく扱うこともできます。
(ただ、Deviceしか使わないなら、io::streamを使ったほうが余計な機能がなくていいかと思います)
そして、Filterを複数個使えば、文字列中の単語を置き換えて、データを圧縮して、暗号化して…といくつものデータ加工を行うことができます。
Filterの解説はここまでです。
さて、おいておかれてしまった、文字列"Example characters"の出力ですが、これは単純に、std::cinと同じようにstd::getlineで取得すればOKです。
int main(){ namespace io = boost::iostreams; io::filtering_istream in; in.push(io::gzip_decompressor()); in.push(io::file_descriptor_source("gzip_file.gz")); std::string str; std::getline(in, str); std::cout << str << std::endl; return 0; }
せっかくなのでIostreamsにある関数、copyを使ってみましょう。
#include <boost/iostreams/copy.hpp> int main(){ namespace io = boost::iostreams; io::filtering_istream in; in.push(io::gzip_decompressor()); in.push(io::file_descriptor_source("gzip_file.gz")); std::string str; io::copy(in, io::back_inserter(str)); std::cout << str << std::endl; return 0; }
copyは1行といわず全データをコピーします。
ところでこのFilterは定期的に掃除をしなくても大丈夫なのかしら。*2