Как подключить сериализацию Boost и iostreams для сериализации и сжатия объекта в строку?

StackOverflow https://stackoverflow.com/questions/1753469

Вопрос

Я использую библиотеку сериализации 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();
}

В результате некоторые данные застревают где-то в буфере потока, и я всегда получаю несколько полных блоков (16 КБ или 32 КБ) сжатых данных, хотя знаю, что они должны быть 43 КБ или около того, учитывая (действительный) вывод, который я получаю от использования мой метод saveGZFile.По-видимому, подключение ofstream закрывается и сбрасывается правильно, но подключение ostringstream - нет.

Любая помощь?(Это мой первый вопрос о stackoverflow — помогите мне, ребята, вы моя единственная надежда!)

Это было полезно?

Решение

Возвращаясь к этому вопросу, я понял, что, должно быть, исправил это где-то в прошлом году (поскольку сейчас я использую 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;
}

Другие советы

Я сам не запускал код, но лучше всего использовать out.strict_sync() что применимо flush() каждому filter/device в трубопроводе.Хотя я не могу сказать, если gzip_compressor является flushable.Если это не так, то strict_sync() вернет false, и sync() было бы более уместно.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top