如何连接Boost序列化& iostreams序列化& gzip一个字符串的对象?

时间:2009-11-18 03:35:07

标签: c++ boost boost-serialization boost-iostreams ostringstream

我一直在使用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)压缩数据给定(有效)输出I从使用我的saveGZFile方法获得。显然是挂起了ofstream关闭并正确刷新,但挂钩ostringstream却没有。

有任何帮助吗? (这是我的第一个stackoverflow问题 - 帮助我,伙计们,你们是我唯一的希望!)

2 个答案:

答案 0 :(得分:19)

回到这个问题,我意识到我必须在去年的某个时候修复它(因为我现在正在使用saveGZString)。挖掘看我如何修复它,它非常愚蠢/简单:

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();
}

让整个链条超出范围,它的工作原理!整齐!这是我的装载完整性:

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;
}

答案 1 :(得分:1)

我自己没有运行代码,但最好的猜测是使用out.strict_sync()flush()应用于管道中的每个filter / device。但是,如果gzip_compressorflushable,我似乎无法说出来。如果不是,则strict_sync()将返回false,sync()将更合适。