C++でメモリストリームを扱う方法

C++はファイルストリームやストリングストリームはあるのに、何故かメモリストリームが存在しない!!!


今回はストリングストリームをメモリストリームとして扱う方法を紹介する。
まずは出力ストリームの使い方だ。

#include <iostream>
#include <sstream>
#include <vector>

int main()
{
    // データの書き込み
    char n[] = { 1, 3, 0, 4, 13, };           // 書き込むデータを用意
    std::ostringstream os;                    // 書き込みインスタンスを作成
    os.write(n, sizeof(n));                   // データを書き込む

    // 書き込んだデータの取得
    std::vector<char> buf(os.str().size());   // ストリームのサイズ分の領域を確保
    memcpy(&buf[0], os.str().data(), os.str().size());    // バッファにコピー

    // コピーしたデータを確認
    for (auto it = buf.begin(); it != buf.end(); ++it) {
        std::cout << static_cast<int>(*it) << " ";
    }
}

出力結果は以下となる。

1 3 0 4 13


ここまでは特に問題ないだろう。
ストリングバッファにバイナリを書き込むのが少し抵抗があるが、機能が存在しないのだから仕方ない。


次は入力ストリームである。こいつが曲者だ。
まずは次のプログラムを見て欲しい。

#include <iostream>
#include <sstream>
#include <vector>

int main()
{
    // データの書き込み
    char n[] = { 1, 3, 0, 4, 13, };         // 書き込むデータを用意
    std::istringstream is(n, sizeof(n));    // インスタンスを作成し、同時に書き込む

    // 書き込んだデータを確認する
    std::string& ss = is.str();
    for (auto it = ss.begin(); it != ss.end(); ++it) {
        std::cout << static_cast<int>(*it) << " ";
    }
}

出力結果は以下となる。

1 3

書き込んだバイナリデータの中にナル文字が入っていた場合、そこで書き込みが中断されてしまう。
次のプログラムはこの問題を回避する。

#include <iostream>
#include <sstream>
#include <vector>

int main()
{
    // データの書き込み
    char n[] = { 1, 3, 0, 4, 13, };            // 書き込むデータを用意
    std::string s(n, n + sizeof(n));           // バイナリから文字列を生成(STLのbegin()とend()の指定方法)
    std::istringstream is(s, std::istringstream::binary);    // インスタンスをバイナリ指定で生成

    // 書き込んだデータを確認する
    std::string& ss = is.str();
    for (auto it = ss.begin(); it != ss.end(); ++it) {
        std::cout << static_cast<int>(*it) << " ";
    }
}

出力結果は以下となる。

1 3 0 4 13


この方法を使うことで入力ストリームでバイナリを扱うことが可能となる。