2010-07-08 17 views
16

Ho un file .gz da 3 terabyte e voglio leggere il suo contenuto non compresso riga per riga in un programma C++. Dato che il file è abbastanza grande, voglio evitare di caricarlo completamente in memoria.Come leggere un file .gz riga per riga in C++?

Qualcuno può pubblicare un semplice esempio di farlo?

+1

Dovrete ** ** devi decomprimerlo per essere in grado di leggerlo. Tuttavia, ciò che puoi fare è decomprimerlo in memoria, e non sul disco. E 'questo che intendevi? – ereOn

+1

Non è possibile - non ci sono linee da leggere. –

+0

cos'è 3T? e @Neil è giusto che un file .gz non abbia 'linee' come formato binario. – TJB

risposta

13

È molto probabilmente dovrà utilizzare deflate di ZLib, ad esempio è disponibile dal loro site

In alternativa si può avere uno sguardo a BOOST C++ wrapper

L'esempio da pag BOOST (decomprime i dati da un file e lo scrive a uscita standard)

#include <fstream> 
#include <iostream> 
#include <boost/iostreams/filtering_streambuf.hpp> 
#include <boost/iostreams/copy.hpp> 
#include <boost/iostreams/filter/zlib.hpp> 

int main() 
{ 
    using namespace std; 

    ifstream file("hello.z", ios_base::in | ios_base::binary); 
    filtering_streambuf<input> in; 
    in.push(zlib_decompressor()); 
    in.push(file); 
    boost::iostreams::copy(in, cout); 
} 
0

Non è possibile farlo perché * .gz non ha "righe".

Se i dati compressi hanno una nuova riga, è necessario decomprimerla. Non è necessario decomprimere tutti i dati contemporaneamente, lo si può fare in blocchi e inviare le stringhe al programma principale quando si incontrano caratteri di nuova riga. * .gz può essere decompresso utilizzando zlib.

2

La libreria zlib supporta la decompressione di file in memoria in blocchi, quindi non è necessario decomprimere l'intero file per elaborarlo.

8

Per qualcosa che verrà utilizzato regolarmente, probabilmente si desidera utilizzare uno dei suggerimenti precedenti. In alternativa, si può fare

gzcat file.gz | yourprogram 

e hanno yourprogram lettura da cin. Ciò decomprimerà le parti del file in memoria come è necessario e invierà l'output non compresso a yourprogram.

1

Utilizzando zlib, sto facendo qualcosa in questo senso:

// return a line in a std::vector<char> 
std::vector<char> readline(gzFile f) { 
    std::vector<char> v(256); 
    unsigned pos = 0; 
    for (;;) { 
     if (gzgets(f, &v[ pos ], v.size() - pos) == 0) { 
      // end-of-file or error 
      int err; 
      const char *msg = gzerror(f, &err); 
      if (err != Z_OK) { 
       // handle error 
      } 
      break; 
     } 
     unsigned read = strlen(&v[ pos ]); 
     if (v[ pos + read - 1 ] == '\n') { 
      if (v[ pos + read - 2 ] == '\r') { 
       pos = pos + read - 2; 
      } else { 
       pos = pos + read - 1; 
      } 
      break; 
     } 
     if (read == 0 || pos + read < v.size() - 1) { 
      pos = read + pos; 
      break; 
     } 
     pos = v.size() - 1; 
     v.resize(v.size() * 2); 
    } 
    v.resize(pos); 
    return v; 
} 

EDIT: rimossi due mis-copiati * nell'esempio di cui sopra.

+0

Hmm, questo è stato downvoted almeno due volte. È un esempio funzionante su come usare "basic" zlib IMHO, quindi per favore prendi in considerazione il commento quando vota per rendere un improvviso possibile. – mkluwe

0

Ecco un codice con il quale è possibile leggere normale e zip file riga per riga:

char line[0x10000]; 
FILE *infile=open_file(file); 
bool gzipped=endsWith(file, ".gz"); 
if(gzipped) 
    init_gzip_stream(infile,&line[0]); 
while (readLine(infile,line,gzipped)) { 
    if(line[0]==0)continue;// skip gzip new_block 
    printf(line); 
} 


#include <zlib.h> 
#define CHUNK 0x100 
#define OUT_CHUNK CHUNK*100 
unsigned char gzip_in[CHUNK]; 
unsigned char gzip_out[OUT_CHUNK]; 
///* These are parameters to inflateInit2. See http://zlib.net/manual.html for the exact meanings. */ 
#define windowBits 15 
#define ENABLE_ZLIB_GZIP 32 
z_stream strm = {0}; 
z_stream init_gzip_stream(FILE* file,char* out){// unsigned  
     strm.zalloc = Z_NULL; 
     strm.zfree = Z_NULL; 
     strm.opaque = Z_NULL; 
     strm.next_in = gzip_in; 
     strm.avail_in = 0; 
     strm.next_out = gzip_out; 
     inflateInit2 (& strm, windowBits | ENABLE_ZLIB_GZIP); 
    return strm; 
} 

bool inflate_gzip(FILE* file, z_stream strm,size_t bytes_read){ 
      strm.avail_in = (int)bytes_read; 
      do { 
       strm.avail_out = OUT_CHUNK; 
       inflate (& strm, Z_NO_FLUSH); 
//    printf ("%s",gzip_out); 
      }while (strm.avail_out == 0); 
      if (feof (file)) { 
       inflateEnd (& strm); 
       return false; 
      } 
    return true;// all OK 
} 


char* first_line=(char*)&gzip_out[0]; 
char* current_line=first_line; 
char* next_line=first_line; 
char hangover[1000]; 
bool readLine(FILE* infile,char* line,bool gzipped){ 
    if(!gzipped) 
     return fgets(line, sizeof(line), infile) != NULL; 
    else{ 
     bool ok=true; 
     current_line=next_line; 
     if(!current_line || strlen(current_line)==0 || next_line-current_line>OUT_CHUNK){ 
      current_line=first_line; 
      size_t bytes_read = fread (gzip_in, sizeof (char), CHUNK, infile); 
      ok=inflate_gzip(infile,strm,bytes_read); 
      strcpy(line,hangover); 
     } 
     if(ok){ 
      next_line=strstr(current_line,"\n"); 
      if(next_line){ 
       next_line[0]=0; 
       next_line++; 
       strcpy(line+strlen(hangover),current_line); 
       hangover[0]=0; 
      }else{ 
       strcpy(hangover,current_line); 
       line[0]=0;// skip that one!! 
      } 
     } 
     return ok; 
    } 
} 
Problemi correlati