c++ boost boost-serialization boost-iostreams ostringstream

c++ - ¿Cómo conectar la serialización y iostreams de Boost para serializar y convertir gzip un objeto en cadena?



boost-serialization boost-iostreams (2)

He estado usando la biblioteca de serialización de Boost, que en realidad es bastante agradable, y me permite crear envoltorios simples para guardar mis objetos serializables en cadenas, de esta manera:

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

El caso es que descubrí la necesidad de comprimir mis datos serializados también, así que estoy buscando hacerlo con los filtros en boost :: iostreams. Descubrí cómo hacerlo con éxito con los archivos:

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

Pero no puede encontrar la forma de guardar correctamente en una cadena comprimida. El problema es que no estoy descargando la cadena de filtros, pero he intentado hacer estallar y sincronizar y nada parece funcionar. Aquí está mi código roto:

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

Como resultado, algunos datos se quedan atascados en el búfer de flujo en algún lugar, y siempre termino con unos pocos bloques completos (16K o 32K) de datos comprimidos cuando sé que deberían tener 43K más o menos dado el resultado (válido) que obtengo del uso mi método saveGZFile. Aparentemente, conectar el flujo de corriente se cierra y se vacía correctamente, pero conectar el ostringstream no.

¿Alguna ayuda? (Esta es mi primera pregunta de stackoverflow - ¡ayúdenme, chicos, sois mi única esperanza!)


No he ejecutado el código yo mismo, pero mi mejor out.strict_sync() es usar out.strict_sync() que aplica flush() a cada filter / device en la tubería. Sin embargo, parece que no puedo decir si gzip_compressor es flushable . Si no es así, strict_sync() devolverá falso, y sync() sería más apropiado.


Volviendo a esta pregunta, me di cuenta de que debo haberlo solucionado en algún momento el año pasado (ya que estoy usando saveGZString en este momento). Excavar para ver cómo lo arreglé, fue bastante tonto / 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(); }

¡Solo deja que toda la cadena se salga del alcance y funciona! ¡Ordenado! Aquí está mi cargador para completar:

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