2010-07-08 38 views
16

Tengo 3 terabytes .gz y quiero leer su contenido sin comprimir línea por línea en un programa C++. Como el archivo es bastante grande, quiero evitar cargarlo completamente en la memoria.¿Cómo leer un archivo .gz línea por línea en C++?

¿Alguien puede publicar un ejemplo simple de hacerlo?

+1

Usted ** ** tiene que descomprimirlo para poder leerlo. Sin embargo, lo que puede hacer es descomprimirlo en la memoria y no en el disco. Es eso lo que querías decir ? – ereOn

+1

No puede - no hay líneas para leer. –

+0

¿Qué es 3T? y @Neil es correcto, un archivo .gz no tendrá 'líneas', es un formato binario. – TJB

Respuesta

13

Es más probable que tenga que utilizar desinflado de zlib ejemplo está disponible en su site

Alternativamente, puede echar un vistazo a BOOST C++ wrapper

El ejemplo de la página BOOST (descomprime datos de un archivo y lo escribe a la salida estándar)

0

No se puede hacer eso, porque * .gz no tiene "líneas".

Si los datos comprimidos tienen líneas nuevas, tendrá que descomprimirlo. No tiene que descomprimir todos los datos a la vez, ya sabe, puede hacerlo en fragmentos y enviar secuencias al programa principal cuando encuentre caracteres de nueva línea. * .gz se puede descomprimir usando zlib.

2

La biblioteca zlib admite la descompresión de archivos en la memoria en bloques, por lo que no tiene que descomprimir el archivo completo para procesarlo.

8

Para algo que va a ser utilizado con regularidad, es probable que desee utilizar una de las sugerencias anteriores. Alternativamente, se puede hacer

gzcat file.gz | yourprogram 

y tienen yourprogram lectura de cin. Esto descomprimirá partes del archivo en la memoria cuando sea necesario y enviará la salida sin comprimir al yourprogram.

1

Usando zlib, estoy haciendo algo en este sentido:

// 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: quitados los dos mis-copiados * en el ejemplo anterior.

+0

Hmm, esto ha sido downvoted al menos dos veces. Es un ejemplo de trabajo sobre cómo usar zlib "básico" en mi humilde opinión, así que considere comentar al votar esto para hacer una mejora posible. – mkluwe

0

Aquí hay un código con el que se puede leer normal y comprimido archivos línea por línea:

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