2011-10-04 9 views
7

dopo alcuni giorni di esperimenti con i buffer di protocollo, ho provato a comprimere i file con . Con Python questo è abbastanza semplice da fare e non richiede alcun gioco con flussi.Semplice esempio di funzionamento di GzipOutputStream e GzipInputStream con i buffer di protocollo

Poiché la maggior parte del nostro codice è scritta in C++, mi piacerebbe comprimere/ decomprimere i file nella stessa lingua. Ho provato la biblioteca gzip spinta, ma non sono riuscito a farlo funzionare (non compressione):

int writeEventCollection(HEP::MyProtoBufClass* protobuf, std::string filename, unsigned int compressionLevel) { 
      ofstream file(filename.c_str(), ios_base::out | ios_base::binary); 
      filtering_streambuf<output> out; 
      out.push(gzip_compressor(compressionLevel)); 
      out.push(file); 
      if (!protobuf->SerializeToOstream(&file)) {//serialising to wrong stream I asume 
        cerr << "Failed to write ProtoBuf." << endl; 
        return -1; 
      } 
      return 0; 
    } 

Ho cercato per gli esempi che utilizzano GzipOutputStream and GzipInputStream con buffer protocollo, ma non riuscivo a trovare un esempio di lavoro.

Come probabilmente avete notato, ormai io sono un principiante al meglio con i flussi e sarebbe davvero apprezzare un esempio completamente funzionante come in http://code.google.com/apis/protocolbuffers/docs/cpptutorial.html (ho il mio address_book, come faccio a salvarlo in un file gziped?)

Grazie in anticipo.

MODIFICA: Esempi di lavoro.

Esempio 1 in seguito alla risposta qui su StackOverflow

int writeEventCollection(shared_ptr<HEP::EventCollection> eCollection, 
std::string filename, unsigned int compressionLevel) { 
filtering_ostream out; 
out.push(gzip_compressor(compressionLevel)); 
out.push(file_sink(filename, ios_base::out | ios_base::binary)); 
if (!eCollection->SerializeToOstream(&out)) { 
       cerr << "Failed to write event collection." << endl; 
       return -1; 
} 

return 0; 
} 

Esempio 2 seguente risposta sul Google's Protobuf discussion group:

int writeEventCollection2(shared_ptr<HEP::EventCollection> 
eCollection, std::string filename, 
         unsigned int compressionLevel) { 
using namespace google::protobuf::io; 
int filedescriptor = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 
       S_IREAD | S_IWRITE); 
if (filedescriptor == -1) { 
         throw "open failed on output file"; 
       } 
google::protobuf::io::FileOutputStream file_stream(filedescriptor); 
GzipOutputStream::Options options; 
options.format = GzipOutputStream::GZIP; 
options.compression_level = compressionLevel; 
google::protobuf::io::GzipOutputStream gzip_stream(&file_stream, 
options); 
if (!eCollection->SerializeToZeroCopyStream(&gzip_stream)) { 
    cerr << "Failed to write event collection." << endl; 
    return -1; 
    } 
close(filedescriptor); 
return 0; 
} 

Alcuni commenti sulla performance (lettura attuale formato e la scrittura protobuf 11146 file): Esempio 1:

real 13m1.185s 
user 11m18.500s 
sys  0m13.430s 
CPU usage: 65-70% 
Size of test sample: 4.2 GB (uncompressed 7.7 GB, our current compressed format: 7.7 GB) 

Esempio 2:

real 12m37.061s 
user 10m55.460s 
sys  0m11.900s 
CPU usage: 90-100% 
Size of test sample: 3.9 GB 

Sembra che il metodo di Google utilizza la CPU in modo più efficiente, è leggermente più veloce (anche se mi aspetto che questo sia all'interno di accuratezza) e produce un dataset ~ 7% più piccola con la stessa impostazione di compressione.

+0

Si noti che il problema fondamentale qui non è relativo ai buffer del protocollo: qualsiasi esempio di "scrittura/catena gzip tramite un flusso" dovrebbe funzionare. –

risposta

2

La tua ipotesi è corretta: il codice che hai postato non funziona perché stai scrivendo direttamente allo ofstream anziché tramite lo filtering_streambuf. Per fare questo lavoro è possibile utilizzare filtering_ostream invece:

ofstream file(filename.c_str(), ios_base::out | ios_base::binary); 
filtering_ostream out; 
out.push(gzip_compressor(compressionLevel)); 
out.push(file); 

if (!protobuf->SerializeToOstream(&out)) { 
    // ... etc. 
} 

O, più succintamente, utilizzando file_sink:

filtering_ostream out; 
out.push(gzip_compressor(compressionLevel)); 
out.push(file_sink(filename, ios_base::out | ios_base::binary)); 

if (!protobuf->SerializeToOstream(&out)) { 
    // ... etc. 
} 

Spero che questo aiuta!

+0

Grazie! Questo ha davvero aiutato. Ora sta funzionando come dovrebbe. – DragonTux