25

J'utilise la bibliothèque de sérialisation Boost, qui est en fait assez agréable, et me permet de faire des emballages simples pour sauver mes objets sérialisables à cordes, comme ceci:Comment connecter une sérialisation Boost & iostreams pour sérialiser & gzip un objet en chaîne?

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

La chose est, je viens de trouver la J'ai aussi besoin de compresser mes données sérialisées, donc je cherche à le faire avec les filtres de boost :: iostreams. J'ai compris comment le faire avec succès avec des fichiers:

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

Mais ne peut pas comprendre comment enregistrer correctement à une chaîne compressée. Le problème est que je ne vidange pas la chaîne de filtres, mais j'ai essayé de sauter et de synchroniser et rien ne semble fonctionner. Voici mon code cassé:

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

En conséquence, certaines données se coince dans le tampon de flux quelque part, et je finis toujours avec aa quelques blocs complets (16K ou 32K) de données compressées quand je sais que ce doit être 43K ou alors donné la sortie (valide) que j'obtiens en utilisant ma méthode saveGZFile. Apparemment, accrocher l'ofstream se ferme et se rince correctement, mais pas l'ostringstream.

Une aide? (Ceci est ma première question stackoverflow - aidez-moi, les gars, vous êtes mon seul espoir!)

Répondre

19

En revenant à cette question, j'ai réalisé que je devais le réparer l'année dernière (car j'utilise saveGZString en ce moment). Creuser pour voir comment je l'ai fixé, il était assez stupide/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(); 
} 

il suffit de laisser la chaîne hors de portée et ça marche! Soigné! Voici mon chargeur pour l'exhaustivité:

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

Vous pouvez éviter le truc de limitation de portée avec un appel à flush(). f.flush() –

+1

dans le code qui ne fonctionne pas dans ma question, le commentaire dit "' 'oss.flush() ??' "car l'appel' flush() 'sur' ostringstream' ne fonctionnait pas. le truc de limitation de portée est la seule chose qui a fonctionné pour moi. sauf si vous voulez dire que je devrais flush 'f', qui n'a pas de méthode flush (il a une méthode' strict_sync() 'qui est supposée appeler' flush() 'sur tous les périphériques du pipeline, ce que j'ai aussi essayé, en vain). – cce

+0

Merci pour cela - je courais dans le même problème. Aucun vidage disponible et strict_sync n'a eu d'effet. – erikreed

1

Je n'ai pas exécuter le code moi-même, mais ma meilleure estimation est d'utiliser out.strict_sync() qui applique flush() à chaque filter/device en cours. Je ne peux pas dire, cependant, si gzip_compressor est flushable. Si ce n'est pas le cas, alors strict_sync() retournera false, et sync() serait plus approprié.

+0

+1 Ça sent le flush! – fmuecke

+0

En interne, il est affleurant. Mais, il est appliqué à chaque filtre/périphérique de la chaîne. – rcollyer

+1

si je me souviens (il y a longtemps) j'ai essayé 'strict_sync()' et cela n'a pas fonctionné, ainsi que les autres choses dans la ligne frustrée '// XXX ??' dans ma question ... peut-être que cela fonctionne dans le dernier Boost, qui sait. – cce

Questions connexes