2010-07-08 14 views
16

Ich habe 3 Terabyte. GZ-Datei und möchte seinen unkomprimierten Inhalt Zeile für Zeile in einem C++ - Programm lesen. Da die Datei sehr groß ist, möchte ich vermeiden, sie vollständig in den Speicher zu laden.Wie liest man eine .gz-Datei Zeile für Zeile in C++?

Kann jemand ein einfaches Beispiel dafür schreiben?

+1

Sie werden ** müssen ** entpacken Sie es, es lesen zu können. Was Sie jedoch tun können, ist, es in den Speicher und nicht auf die Festplatte zu dekomprimieren. Ist es das, was du meintest ? – ereOn

+1

Sie können nicht - es gibt keine Zeilen zu lesen. –

+0

was ist 3T? und @Neil hat Recht, eine .gz-Datei hat keine Zeilen, das ist ein Binärformat. – TJB

Antwort

13

Sie höchstwahrscheinlich ZLib des abgelassenen verwenden müssen, beispielsweise von ihren site

verfügbar Alternativ können Sie bei BOOST C++ wrapper

Das Beispiel von BOOST Seite einen Blick (dekomprimiert Daten aus einer Datei und schreibt zur Standardausgabe)

#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

Sie können das nicht tun, weil * .gz keine "Zeilen" hat.

Wenn komprimierte Daten Zeilenumbrüche haben, müssen Sie sie dekomprimieren. Sie müssen nicht alle Daten auf einmal dekomprimieren, wissen Sie, Sie können es in Chunks machen und Strings zurück zum Hauptprogramm senden, wenn Sie Newline-Zeichen vorfinden. * .gz kann mit zlib dekomprimiert werden.

2

Die Bibliothek zlib unterstützt das Dekomprimieren von Dateien im Speicher in Blöcken, sodass Sie nicht die gesamte Datei dekomprimieren müssen, um sie zu verarbeiten.

8

Für etwas, das regelmäßig verwendet wird, möchten Sie wahrscheinlich einen der vorherigen Vorschläge verwenden. Alternativ können Sie

gzcat file.gz | yourprogram 

tun und yourprogram Lesen von cin haben. Dadurch werden Teile der Datei im Speicher wie benötigt dekomprimiert und die unkomprimierte Ausgabe an yourprogram gesendet.

1

Mit zlib, ich bin etwas in diese Richtung tun:

// 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: entfernt zwei Fehl kopiert * im Beispiel oben.

+0

Hmm, das wurde mindestens zweimal downvotet. Es ist ein funktionierendes Beispiel dafür, wie man "basic" zlib IMHO verwenden kann, also denke bitte darüber nach, wenn du dies abstimmst, um eine Verbesserung zu ermöglichen. – mkluwe

0

Hier ist ein Code, mit dem Sie normal und ZIP-Dateien Zeile für Zeile lesen:

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