Подтвердить что ты не робот

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

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

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

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

4b9b3361

Ответ 1

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

Ответ 2

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