2010-07-08 3 views
16

У меня есть 3 терабайта .gz-файл и вы хотите читать его несжатое содержимое по очереди в программе на C++. Поскольку файл довольно большой, я хочу, чтобы он полностью не загружался в память.Как читать файл .gz по очереди в C++?

Может ли кто-нибудь опубликовать простой пример этого?

+1

Вы ** должны ** распаковать его, чтобы быть в состоянии прочитать его. Однако, что вы можете сделать, это распаковать его в память, а не на диск. Это ты имел в виду? – ereOn

+1

Вы не можете - нет строк для чтения. –

+0

Что такое 3Т? и @Neil прав. Файл в формате .gz не будет иметь 'lines' его двоичный формат. – TJB

ответ

13

Вы, скорее всего, придется использовать Deflate ZLIB, в пример можно получить их site

В качестве альтернативы вы можете посмотреть на BOOST C++ wrapper

Пример из BOOST страницы (распаковывает данные из файла и записывает его к стандартному выходу)

#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

Вы не можете этого сделать, потому что * .gz не имеет «линий».

Если сжатые данные имеют символы новой строки, вам придется распаковать его. Вы не должны распаковывать все данные одновременно, вы знаете, вы можете сделать это в кусках и отправлять строки обратно в основную программу, когда вы сталкиваетесь с символами новой строки. * .gz можно распаковать, используя zlib.

2

Библиотека zlib поддерживает распаковку файлов в памяти в блоках, поэтому вам не нужно распаковывать весь файл, чтобы обработать его.

8

Для чего-то, что будет использоваться регулярно, вы, вероятно, захотите использовать одно из предыдущих предложений. Кроме того, вы можете сделать

gzcat file.gz | yourprogram 

и имеют yourprogram чтение из КИН. Это приведет к распаковке частей файла в памяти по мере необходимости и отправке несжатого вывода в yourprogram.

1

Используя zlib, я делаю что-то вдоль этих линий:

// 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: Удалены два неправильно скопированные * в приведенном выше примере.

+0

Хмм, это было уменьшено минимум два раза. Это рабочий пример о том, как использовать «базовый» zlib IMHO, поэтому, пожалуйста, рассмотрите комментарий при голосовании, чтобы сделать импровизацию возможным. – mkluwe

0

Вот код, с помощью которого вы можете прочитать обычный и сжатые файлы построчно:

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