如何使用zlib创建与gz兼容的文件?

时间:2014-05-21 07:21:30

标签: c++ c zlib gz

我想使用 zlib 与C ++生成 gz兼容的输出文件。

我安装了zlib的开发人员包,根据我的理解,可以在Unix和Windows上创建与gz兼容的文件。

sudo aptitude install libz-dev

虽然我写了一个C ++程序,但我认为我在相关点上遵循了usage example。我还将示例编译为zpipe.c未更改。

唉,我得到的是与gz兼容的输出。

$ ./zpipe.x < data.txt > x.gz
$ file x.gz
x.gz: data
$ gunzip x.gz 
gzip: x.gz: not in gzip format

我认为这里的原因可能是,因为deflateSetHeader没有被调用。所以我把它添加到我自己的源代码中,即(摘录,你可以找到full code here):

struct DeflateWrap { // RAII wrapper
  z_stream strm_ ; // C-Struct from zlib.h
  explicit DeflateWrap() : strm_{} {
    strm_.zalloc = Z_NULL;
    strm_.zfree = Z_NULL;
    strm_.opaque = Z_NULL;
    auto ret = deflateInit2(&strm_, LEVEL,
                 Z_DEFLATED, 15, 9, Z_DEFAULT_STRATEGY); 
    if(ret != Z_OK) throw std::runtime_error("Error ZLib-Init");
  }
  // ...more, eg. operator-> and *...
};

void pack(const string& infn) {
  DeflateWrap dwrap {};
  //...
  dwrap->avail_in = indata.size();
  dwrap->next_in = reinterpret_cast<unsigned char*>(indata.data());
  gz_header header {0}; // <<< HEADER HERE
  header.name = const_cast<unsigned char*>(
    reinterpret_cast<const unsigned char*>(infn.c_str()));
  header.comment = Z_NULL;
  header.extra = Z_NULL;
  bool first = true;
  do {
    dwrap->avail_out = outdata.size();
    dwrap->next_out = reinterpret_cast<unsigned char*>(outdata.data());
    if(first) {
      cerr << deflateSetHeader(&(dwrap.strm_), &header); // <<< SET HDR HERE
      first = false;
    }
    deflate(&(dwrap.strm_), Z_FINISH); // zlib.h: this packs
    auto toWrite = outdata.size() - dwrap->avail_out;
    outf.write(outdata.data(), toWrite);
  } while (dwrap->avail_out == 0);
}

根据我的解释,我跟随deflateSetHeader deflateInit2

  • 我甚至使用了deflateInit代替deflateSetHeader,可能是不必要的
  • deflateInit2
  • 之后立即致电deflateSetHeader
  • deflate的来电是在-2
  • 的任何来电之前

...我仍然从Z_STREAM_ERROR电话中获得deflateSetHeader,即zpipe.c。虽然,我生成的输出可以用SET_BINARY_MODE(stdin); SET_BINARY_MODE(stdout); 解压缩,因此它可能完全错误,是吗?

知道如何设置与gz兼容的标头吗?

更新

在我看来,我使用C ++ - 吊坠

ifstream inf{ infn, ifstream::binary };
ofstream outf { infn + ".gz", ofstream::binary };

打开这样的文件:

zpipe.c

另外,我想知道为什么我制作的{{1}}示例也没有像我之前描述的那样制作一个与gunzip兼容的文件。根据我的阅读manual它应该。

2 个答案:

答案 0 :(得分:1)

虽然我阅读了deflateSetHeader的文档,但输出文件 gz兼容,但是有一点暗示它可能不是这样。

  

该库支持以gzip(.gz)格式读取和写入具有类似于stdio的接口的文件,使用以&#34; gz&#34;开头的函数。 gzip格式与zlib格式不同。 gzip是一个gzip包装器,在RFC 1952中有记录,包含一个deflate流。

因此,当我使用不同的函数集gz...时,我得到gz兼容的输出更简单的代码:

struct GzWrite { // RAII-Wrapper
    gzFile gz_ ; // C-Struct aus zlib.h
    explicit GzWrite(const string& filename)
        : gz_{gzopen(filename.c_str(),"wb9")}
    {
        if(gz_==NULL) throw std::runtime_error(strerror(errno));
    }
    ~GzWrite() {
        gzclose(gz_);
    }
    int write(const char* data, size_t len) {
        return gzwrite(gz_, data, len);
    }
    GzWrite(const GzWrite&) = delete; // keine Kopie
    GzWrite& operator=(const GzWrite&) = delete; // keine Zuweisung
};

void packe(const string& infn) {
    vector<char> indata = lese(infn); // lese Eingabe
    GzWrite gz{infn+".gz"}; // initialisiere Ausgabe
    auto res = gz.write(indata.data(), indata.size());
    if(res==0) throw std::runtime_error("Fehler beim Schreiben");
}

答案 1 :(得分:0)

windowBits也可以是-8 ..- 15用于原始收缩。在这种情况下,-windowBits确定窗口大小。然后deflate()将生成没有zlib头或尾部的原始deflate数据,并且不会计算adler32检查值。

对于可选的gzip编码,

windowBits也可以大于15。向windowBits添加16,在压缩数据周围编写一个简单的gzip头和尾部,而不是zlib包装器。 gzip头文件没有文件名,没有额外数据,没有注释,没有修改时间(设置为零),没有头文件crc,操作系统将设置为255(未知)。如果正在编写gzip流,则strm-&gt; adler是crc32而不是adler32。