2009-11-18 14 views
25

He estado usando la biblioteca Boost serialización, que en realidad es bastante agradable, y me permite hacer simples envoltorios para guardar mis objetos serializables a las cadenas, así:Cómo conectar la serialización de Boost y iostreams para serializar y convertir gzip un objeto en una cadena?

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

Lo que pasa es que acabo de encontrar la necesito comprimir mis datos serializados también, así que estoy buscando hacerlo con los filtros en boost :: iostreams. Me di cuenta de 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 manera de guardar correctamente a 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 queda atascado en el búfer de la secuencia en alguna parte, y siempre termino con aa pocos bloques completos (16K o 32K) de datos comprimidos cuando sé que debería ser 43K más o menos dado el resultado (válido) que obtengo de usar mi método saveGZFile. Aparentemente, conectar el flujo de corriente se cierra y se vacía correctamente, pero conectar el ostringstream no.

¿Algún ayuda? (Esta es mi primera pregunta StackOverflow - me ayude, chicos, eres mi única esperanza!)

Respuesta

19

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 me fijo, que era 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(); 
} 

Sólo vamos a toda la cadena de ir fuera de 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; 
} 
+0

Puede evitar el truco de limitación del alcance con una llamada a flush(). f.flush() –

+1

en el código que no funciona en mi pregunta, el comentario dice "' oss.flush() ?? '" porque la llamada 'flush()' en 'ostringstream' no funcionaba. el truco de limitación de alcance es lo único que funcionó para mí. a menos que quieras decir que debería tirar 'f', que no tiene un método de enjuague (tiene un método' strict_sync() 'que se supone que llama a' flush() 'en cada dispositivo en la tubería, que también intenté, en vano). – cce

+0

Gracias por esto, me encontré con el mismo problema. No hay descarga disponible y strict_sync no tuvo ningún efecto. – erikreed

1

no he ejecutar el código, pero mi mejor conjetura es utilizar out.strict_sync() que se aplica a todos los flush()filter/device En la tuberia. Parece que no puedo decir, sin embargo, si gzip_compressor es flushable. Si no es así, entonces strict_sync() devolverá falso, y sync() sería más apropiado.

+0

+1 ¡Eso huele a enrojecimiento! – fmuecke

+0

Internamente, es al ras. Pero, se aplica enrasado a cada filtro/dispositivo de la cadena. – rcollyer

+1

según recuerdo (hace mucho tiempo) Probé 'strict_sync()' y no funcionó, así como las otras cosas en la frustrada línea '// XXX ??' en mi pregunta ... tal vez funciona en el último Boost, quién sabe. – cce

Cuestiones relacionadas