ファイルディスクリプタ や FILEポインタ を C++ iostream から使う | 小人閑居して不全を為す

ファイルディスクリプタ や FILEポインタ を C++ iostream から使う

同期入出力処理を行うために、C++ライブラリは iostream を提供している。
C++ iostram は、整形データの入出力を行える。
また、std::stream_iterator / std::streambuf_iterator を使えば、反復子を通じて入出力処理が行える。
さらに、STL との相性がよいため、C++ アルゴリズムと組み合わせることも可能となる。

UNIXシステムコールやCライブラリ (例えば、popen() や pipe()) を使う場合、ファイルディスクリプタ や FILEポインタ で入出力を行う必要がある。
そのため、どうしてもCライクなコードを書く必要が出てくる。

そこで、今回は ファイルディスクリプタ や FILEポインタ を、C++ iostream 経由で入出力する方法について説明する。
ごりごり自分で std::streambuf の派生クラスを作ってもよいが、boost C++ ライブラリ の iostreams で既に実装されている。

boost iostreams は ファイルディスクリプタ を C++ iostream 経由で入出力するクラスを提供している。
次の関数を使えば FILEポインタからファイルディスクリプタが取得できるため、以降はファイルディスクリプタについてのみ説明する。

#include <stdio.h>
int fileno(FILE *stream);


ファイルディスクリプタから C++ iostream クラスを生成する方法は次のとおり。

入力用(std::istream の派生クラス)の場合
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>

int fd = ...;
namespace io = boost::iostreams;
io::stream<io::file_descriptor_source> isfd(fd);

出力用(std::ostream の派生クラス)の場合
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>

int fd = ...;
namespace io = boost::iostreams;
io::stream<io::file_descriptor_sink> osfd(fd);

入出力用(std::iostream の派生クラス)の場合
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>

int fd = ...;
namespace io = boost::iostreams;
io::stream<io::file_descriptor> iosfd(fd);

また、それぞれのコンストラクタの第2引数に true を指定すると、C++ iostream クラスが破棄されるときに、ファイルディスクリプタをクローズしてくれる。
例えば、入力用(std::istream の派生クラス) の場合、次のようにする。
io::stream<io::file_descriptor_source> isfd(fd, true);


std::streambuf クラスの派生クラスが欲しい場合は、boost/iostreams/stream.hpp の代わりにboost/iostreams/stream_buffer.hppをインクルードして、io::stream の代わりに io::stream_buffer を使用する。
例えば、出力用の場合、次のようになる。
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>

int fd = ...;
namespace io = boost::iostreams;
io::stream_buffer<io::file_descriptor_sink> osbfd(fd);


サンプルコードとして、ファイルディスクリプタからの入力データを全て標準出力に出力して、ファイルディスクリプタをクローズするコードを示す。

#include <iostream>

#include <boost/iostreams/stream_buffer.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>

int fd = ...;

namespace io = boost::iostreams;
io::stream_buffer<io::file_descriptor_source> isb(fd, true);
std::cout << &isb;