26

私はBoostシリアル化ライブラリを使用してきましたが、これは実際には非常に優れており、次のように、シリアル化可能なオブジェクトを文字列に保存するための単純なラッパーを作成できます。

namespace bar = boost::archive;
namespace bio = boost::iostreams;

template <class T> inline std::string saveString(const T & o) {
 std::ostringstream oss;
 bar::binary_oarchive oa(oss);
 oa << o;
 return oss.str();
}
template <class T> inline void saveFile(const T & o, const char* fname) {
 std::ofstream ofs(fname, std::ios::out|std::ios::binary|std::ios::trunc);
 bar::binary_oarchive oa(ofs);
 oa << o;
}
template <class T> inline void loadFile(T & o, const char* fname) {
 std::ifstream ifs(fname, std::ios::in|std::ios::binary);
 assert(ifs.good()); // XXX catch if file not found
 bar::binary_iarchive ia(ifs);
 ia >> o;
}

問題は、シリアル化されたデータも圧縮する必要があることを発見したので、boost::iostreamsのフィルターを使用してそれを行うことを検討しています。私はファイルでそれをうまく行う方法を考え出しました:

template <class T> inline void saveGZFile(const T & o, const char* fname) {
 std::ofstream ofs(fname, std::ios::out|std::ios::binary|std::ios::trunc);
 bio::filtering_streambuf<bio::output> out;
 out.push(boost::iostreams::gzip_compressor());
 out.push(ofs);
 bar::binary_oarchive oa(out);
 oa << o;
}
template <class T> inline void loadGZFile(T & o, const char* fname) {
 std::ifstream ifs(fname, std::ios::in|std::ios::binary);
 assert(ifs.good()); // XXX catch if file not found
 bio::filtering_streambuf<bio::input> in;
 in.push(bio::gzip_decompressor());
 in.push(ifs);
 bar::binary_iarchive ia(in);
 ia >> o;
}

しかし、圧縮された文字列に正しく保存する方法を理解することはできません。問題は、フィルターのチェーンをフラッシュしていないことですが、ポップと同期を試しましたが、何も機能しないようです。これが私の壊れたコードです:

template <class T> inline std::string saveGZString(const T & o) {
 std::ostringstream oss;
 bio::filtering_streambuf<bio::output> out;
 out.push(bio::gzip_compressor());
 out.push(oss);
 bar::binary_oarchive oa(out);
 oa << o;
 // XXX out.pop() twice?  out.strict_sync()??  oss.flush()??
 return oss.str();
}

その結果、一部のデータがストリームバッファのどこかにスタックし、43K程度であることがわかっている場合、圧縮データの完全なブロック(16Kまたは32K)が常にいくつかあります。私のsaveGZFileメソッド。どうやらofstreamを接続すると、適切に閉じてフラッシュしますが、ostringstreamを接続してもそうではありません。

何か助けはありますか?(これは私の最初のstackoverflowの質問です—助けてください、みんな、あなたは私の唯一の希望です!)

4

2 に答える 2

22

Returning to this question, I realized I must've fixed it sometime last year (as I'm using saveGZString right now). Digging to see how I fixed it, it was pretty silly/simple:

namespace bar = boost::archive;
namespace bio = boost::iostreams;

template <typename T> inline std::string saveGZString(const T & o) {
        std::ostringstream oss;
        { 
                bio::filtering_stream<bio::output> f;
                f.push(bio::gzip_compressor());
                f.push(oss);
                bar::binary_oarchive oa(f);
                oa << o;
        } // gzip_compressor flushes when f goes out of scope
        return oss.str();
}

Just let the whole chain go out of scope and it works! Neat! Here's my loader for completeness:

template <typename T> inline void loadGZString(T & o, const std::string& s) {
        std::istringstream iss(s);
        bio::filtering_stream<bio::input> f;
        f.push(bio::gzip_decompressor());
        f.push(iss);
        bar::binary_iarchive ia(f);
        ia >> o;
}
于 2011-02-27T07:50:44.213 に答える
1

私は自分でコードを実行していませんが、パイプライン内のすべての/にout.strict_sync()適用されるコードを使用するのが最善の推測です。とはいえ、そうだとは言えないようです。そうでない場合は、falseを返し、より適切になります。flush()filterdevicegzip_compressorflushablestrict_sync()sync()

于 2009-11-20T14:57:54.703 に答える