如何在c中读取一个巨大的.gz文件(超过5 gig未压缩)

时间:2009-12-27 11:11:35

标签: c++ c 64-bit gzip gz

我有一些.gz压缩文件,大约5-7gig未压缩。 这些是平面文件。

我编写了一个程序,它接受一个未压缩的文件,并且每行读取一行,这非常有效。

现在我希望能够在内存中打开压缩文件并运行我的小程序。

我已经研究过zlib,但我找不到一个好的解决方案。

使用gzread(gzFile,void *,unsigned)加载整个文件是不可能的,因为32位无符号int限制。

我尝试了gzgets,但这几乎使执行时间加倍,而不是使用gzread读取。(我在2gig样本上测试过。)

我也研究过“缓冲”,例如将gzread进程拆分为多个2gig块,使用strcchr找到最后一个换行符,然后设置gzseek。 但gzseek将模拟一个完整的文件解压缩。这很慢。

我没有看到任何理智的解决方案。 我总是可以做一些检查,无论当前行是否实际上有一个换行符(应该只出现在最后一个部分读取的行中),然后从程序中发生这种情况的点读取更多数据。 但这可能会非常难看。

无论如何有任何建议吗?

感谢

编辑: 我不需要立刻拥有整个文件,一次只需要一行,但我有一台相当庞大的机器,所以如果这是最简单的我没有问题。

对于那些建议管道标准输入的人来说,与打开文件相比,我经历了极端的减速。这是我几个月前制作的一个小代码片段,它说明了这一点。

time ./a.out 59846/59846.txt
#       59846/59846.txt
18255221

real    0m4.321s
user    0m2.884s
sys     0m1.424s
time ./a.out <59846/59846.txt
18255221

real    1m56.544s
user    1m55.043s
sys     0m1.512s

源代码

#include <iostream>
#include <fstream>
#define LENS 10000

int main(int argc, char **argv){
  std::istream *pFile;

  if(argc==2)//ifargument supplied
    pFile = new std::ifstream(argv[1],std::ios::in);
  else //if we want to use stdin
    pFile = &std::cin;

  char line[LENS];
  if(argc==2) //if we are using a filename, print it.
    printf("#\t%s\n",argv[1]);

  if(!pFile){
    printf("Do you have permission to open file?\n");
    return 0;
  }

  int numRow=0;
  while(!pFile->eof()) {
    numRow++;
    pFile->getline(line,LENS);
  }
  if(argc==2)
    delete pFile;
  printf("%d\n",numRow);
  return 0;
}  

感谢您的回复,我还在等待金苹果

EDIT2: 使用cstyle FILE指针而不是c ++流要快得多。所以我认为这是要走的路。

感谢您的所有输入

3 个答案:

答案 0 :(得分:5)

gzip -cd compressed.gz | yourprogram

然后继续从stdin逐行读取它,因为它是未压缩的。

编辑:回应您对性能的评论。你说直接读取STDIN比直接读取未压缩文件要慢。不同之处在于缓冲。通常,只要输出可用,管道就会产生STDIN(没有或非常小的缓冲)。您可以从STDIN执行“缓冲块读取”并自行解析读取块以获得性能。

通过使用gzread(),您可以获得相同的结果并获得更好的性能。 (读取一大块,解析块,读取下一个块,重复)

答案 1 :(得分:5)

gzread只读取文件的块,就像使用普通的read()调用一样循环播放。

您需要将整个文件读入内存吗?

如果你需要的是读取行,你可以将一个相当大的块(比如8192个字节)gzread()放入缓冲区,遍历该缓冲区并找到所有'\ n'个字符并将它们作为单独的行处理。你必须保存最后一块,只有一行的一部分,并将其添加到你下次读到的数据中。

你也可以从stdin中读取并调用你的应用程序,如

  

zcat bigfile.gz | ./yourprogram

在这种情况下,你可以在stdin上使用fgets和类似的东西。这也是有益的,因为你在一个处理器上运行解压缩并在另一个处理器上处理数据: - )

答案 2 :(得分:0)

我不知道这是否可以回答你的问题,但我认为这不仅仅是一个评论:

几个月前,我发现维基百科的内容可以像StackOverflow数据转储一样下载。两者都解压缩为XML。

我遇到了如何解析多GB压缩转储文件的描述。实际上,它是由Perl脚本完成的,但与您相关的部分是使用了Bzip2压缩。

Bzip2是一种​​块压缩方案,压缩文件可以拆分为可管理的部分,每个部分单独解压缩

不幸的是,我没有链接与您分享,我不能建议您如何搜索它,除非说它是在维基百科的“数据转储”或“博客”页面上描述的。

编辑:实际上,我有一个link