我想使用 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它应该。
答案 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。