25

Sto usando la libreria Boost serializzazione, che è in realtà piuttosto bello, e mi permette di fare involucri semplici per salvare i miei oggetti serializzabili in stringhe, in questo modo:Come collegare la serializzazione Boost e iostreams per serializzare e gzip un oggetto in stringa?

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

Il fatto è che ho appena trovato il ho bisogno di comprimere anche i miei dati serializzati, quindi sto cercando di farlo con i filtri in boost :: iostreams. Ho capito come farlo con successo con i file:

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

Ma non riesco a capire come salvare correttamente in una stringa compressa. Il problema è che non sto scaricando la catena dei filtri, ma ho provato a scoppiare e sincronizzare e nulla sembra funzionare. Ecco il mio codice di rotta:

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

Di conseguenza alcuni dati rimane incastrato nel buffer di flusso da qualche parte, e finisco sempre con aa pochi isolati completi (16K o 32K) di dati compressi, quando so che dovrebbe essere 43K o così dato l'output (valido) che ottengo dall'usare il mio metodo saveGZFile. Apparentemente collegando l'ofstream si chiude e si svuota in modo corretto, ma non aggancia lo stringstream.

Qualsiasi aiuto? (Questa è la mia prima domanda StackOverflow - aiutami, ragazzi, siete la mia unica speranza!)

risposta

19

Tornando a questa domanda, mi sono reso conto che dovevo averlo risolto l'anno scorso (dato che sto usando saveGZString in questo momento). Scavando per vedere come ho riparato, è stato abbastanza sciocco/semplice:

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

Basta lasciare l'intera catena andare fuori del campo di applicazione e funziona! Neat! Ecco il mio caricatore per completezza:

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

È possibile evitare il trucco di limitazione dell'ambito con una chiamata a flush(). f.flush() –

+1

nel codice non funzionante nella mia domanda, il commento dice "' oss.flush() ?? "" perché chiamare 'flush()' su 'ostringstream' non funzionava. il trucco di limitazione dell'ambito è l'unica cosa che ha funzionato per me. a meno che tu non voglia dire che dovrei scaricare 'f', che non ha un metodo flush (ha un metodo' strict_sync() 'che dovrebbe chiamare' flush() 'su ogni dispositivo nella pipeline, che anch'io ho provato, inutilmente). – cce

+0

Grazie per questo - stavo incontrando lo stesso problema. Nessuno svuotamento disponibile e strict_sync non ha avuto alcun effetto. – erikreed

1

non ho eseguito il codice di me, ma la mia ipotesi migliore è quella di utilizzare out.strict_sync() che si applica ad ogni flush()filter/device nella conduttura. Non riesco a capire, però, se gzip_compressor è flushable. In caso contrario, strict_sync() restituirà false e sync() sarebbe più appropriato.

+0

+1 Che odori di colore! – fmuecke

+0

Internamente, è a filo. Ma, è applicato a livello di ogni filtro/dispositivo nella catena. – rcollyer

+1

come ricordo (molto tempo fa) ho provato 'strict_sync()' e non ha funzionato, così come le altre cose nella riga '// XXX ??' frustrata nella mia domanda ... forse funziona nell'ultimo Boost, chi lo sa. – cce

Problemi correlati