25

Я использую библиотеку подталкивания сериализации, который на самом деле очень приятно, и позволяет мне сделать простые обертки, чтобы сохранить свои сериализуемые объекты в строки, например:Как подключить сериализацию Boost и iostreams для сериализации и gzip объекта в строку?

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К) из сжатых данных, когда я знаю, что это должно быть 43K или так дано (действительный) вывод, который я получаю от использования моего метода saveGZFile. По-видимому, подключение вверх по течению закрывается и прилипает должным образом, но соединение с ним не происходит.

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

ответ

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

Вы можете избежать трюка ограничения области с вызовом flush(). f.flush() –

+1

в нерабочем коде в моем вопросе, в комментарии говорится «' oss.flush() ?? '", потому что вызов 'flush()' в 'ostringstream' не работал. трюк ограничения объема - единственное, что сработало для меня. если вы не имеете в виду, что я должен очищать 'f', который не имеет метода flush (он имеет метод' strict_sync() ', который должен вызывать' flush() 'на каждом устройстве в конвейере, которое также я пытался, но безрезультатно). – cce

+0

Спасибо за это - я столкнулся с той же проблемой. Отсутствие флеша и strict_sync не повлияло. – erikreed

1

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

+0

+1 Это пахнет флешем! – fmuecke

+0

Внутренне, это флеш. Но он применяется для каждого фильтра/устройства в цепочке. – rcollyer

+1

как я помню (давным-давно) Я попробовал 'strict_sync()', и он не работал, как и другие вещи в расстроенной строке '// XXX ?? 'в моем вопросе ... возможно, это работает в последнем Boost, кто знает. – cce