如何分发加载GZIP文件?

时间:2015-03-18 09:19:57

标签: c++ gzip

我有一个gzip文件" dat.gz",原始文件只包含逐行的ascii文本。 .gz文件由' pigz -i'

生成

我想加载" dat.gz"进入几个进程并行数据处理。 程序语言必须是C或C ++。在Linux下

例如,原始文件包含" 1 \ n2 \ n3",我将.gz文件加载到3个进程(p0,p1,p2),以便p0得到" 1& #34;,p1得到" 2"和p3获得" 3"。

我在这里阅读了gz的文件格式:http://tools.ietf.org/pdf/rfc1952.pdf,我发现一个.gz文件的每个块都以" \ x1f \ x8b"开头。所以我用" \ x1f \ x8b"来剪切.gz文件。成块。但是当我使用boost的解压缩库来处理块时,出现了问题。

也许我的方法根本不对。

我的测试.gz文件可以在这里下载:https://drive.google.com/file/d/0B9DaAjBTb3bbcEM1N1c4OEg0SWc/view?usp=sharing

我的C ++测试代码如下。运行" g ++ -std = c ++ 11 test.cpp -lboost_iostreams&& ./a.out" ;.它抛出异常。

  

在抛出一个实例后终止调用   boost :: exception_detail :: clone_impl>'   what():gzip错误   中止

#include <stdio.h>
#include <stdlib.h>
#include <string>

#include <fstream>
#include <iostream>

#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/copy.hpp>
#include <sstream>

//define buffer size of fread: 128KB
#define BUFSIZE 128*1024

void get_first_block(char *fn) {
  FILE* fin = fopen(fn, "rb");
  char buf[BUFSIZE] = {0};
  int pos = 0;

  //skip first 2 byte
  fread(buf, sizeof(char), 2, fin);
  int i;
  while (1) {
    int sz = fread(buf, sizeof(char), BUFSIZE, fin);
    if (sz <= 1) {
      break;
    }
    for (i=0; i<sz-1; ++i) {
      if (buf[i] == (char)0x1f && buf[i+1] == (char)0x8b) {
        break;
      }
    }
    pos += sz;
  }
  //first block start: 0
  //first block end: pos + i -1
  int len = pos+i;
  fseek(fin, 0, SEEK_SET);
  char *blk = (char*)malloc(len);
  fread(blk, 1, len, fin);

  using namespace boost::iostreams;
  filtering_streambuf<input> in;
  in.push( gzip_decompressor() );
  in.push( boost::iostreams::array_source(blk , len) );
  std::stringstream _sstream;
  boost::iostreams::copy(in, _sstream);
  std::cout << _sstream.rdbuf() ;
}

int main() {
  get_first_block("0000.gz");
  return 0;
}

2 个答案:

答案 0 :(得分:0)

.gz文件中不可能存在多个块,也请参阅the Wikipedia article about gzip

  

虽然它的文件格式也允许多个这样的流   连接(压缩文件简单解压缩连接,就好像   它们原本是一个文件),gzip通常用于压缩   只是单个文件。

对于您的测试文件尤其如此,因为如果您另外查看&#34;压缩方法&#34; flag,你可以将搜索字符串扩展为0x1F,0x8B,0x08,它只在测试文件的最开头出现一次。

当尝试将.gz文件拆分为块时,您必须进行更多解析而不是仅查找0x1F,0x8B,因为这也可能出现在压缩数据块或成员的其他部分中。

您必须解析成员和压缩数据。不幸的是,标题只包含未压缩的数据长度,而不是压缩长度,所以你不能跳过压缩数据而不解析它。

压缩数据将是deflate数据(还有其他但未使用的压缩类型),请参阅RFC 1951。对于非压缩放气块(第3.2.4节),标题中有LEN字段,因此您可以轻松跳过这些字段。但遗憾的是,压缩块的标题中没有长度字段,因此您必须完全解析这些字段。

答案 1 :(得分:0)

pigz -i独立压缩每个块,允许在每个块边界进行随机访问。每个块之间是一个空的存储块,以字节序列00 00 ff ff结束。您可以搜索该序列,然后尝试解压缩。您的示例文件中有39个这样的标记。

没有任何东西阻止00 00 ff ff出现在压缩块的中间,而不是标记块边界。所以你应该期望偶尔会得到这样一个边界的错误指示,表示没有解压缩。在这种情况下,只需转到下一个这样的标记。