如何使用miniz创建一个可以通过gzip解压的压缩文件



我在windows平台上用c++写一个程序。我想压缩存储在char[]数组中的一些数据,并将其输出到文件中,然后我将该文件上传到unix服务器,我希望它可以通过gzip -d解压。

经过大量的研究,我选择miniz。另外,我在这里找到了gzip文件格式。

下面是创建gzip文件的代码片段:(对不起,我没有把一些变量的定义;它们在其他地方定义)

unsigned long zsize;
zpkg[0] = 0x1F;
zpkg[1] = 0x8B;
zpkg[2] = 8;
zpkg[3] = 0;
zpkg[4] = 0;
zpkg[5] = 0;
zpkg[6] = 0;
zpkg[7] = 0;
zpkg[8] = 0;
zpkg[9] = 0xFF;
compress2(zpkg + 10, &zsize, pkg, pkgSize, MZ_DEFAULT_LEVEL);
int footerStart = (int)zsize + 10;
mz_ulong crc = mz_crc32(MZ_CRC32_INIT, zpkg + 10, zsize);
zpkg[footerStart] = crc & 0xFF;
zpkg[footerStart + 1] = (crc >> 8) & 0xFF;
zpkg[footerStart + 2] = (crc >> 16) & 0xFF;
zpkg[footerStart + 3] = (crc >> 24) & 0xFF;
zpkg[footerStart + 4] = pkgSize & 0xFF;
zpkg[footerStart + 5] = (pkgSize >> 8) & 0xFF;
zpkg[footerStart + 6] = (pkgSize >> 16) & 0xFF;
zpkg[footerStart + 7] = (pkgSize >> 24) & 0xFF;

然后将zpkg数组输出到文件中。然而,这不起作用;当我用gzip解压它时,错误消息是:

gzip: data stream error
gzip: test.gz: uncompress failed
谁能指出我做错了什么吗?

感谢Mark Adler和Michael,我想出了一个可行的解决方案。

首先,正如Mark指出的,我应该让miniz返回一个原始的deflate数据流。这可以通过将-MZ_DEFAULT_WINDOW_BITS(注意负号)作为第四个参数传递给mz_deflateInit2()来实现。查看miniz源代码,compress2()函数最终使用MZ_DEFAULT_WINDOW_BITS调用mz_deflateInit2(),这意味着添加zlib页眉和页脚。最简单的解决方法就是在这里加一个负号,这样我就可以继续使用compress2()函数了。(这对我来说有效,因为我只在一个地方调用这个函数)

第二,正如Michael指出的,CRC码应该在未压缩的数据上计算。所以我像这样修改:

mz_ulong crc = mz_crc32(MZ_CRC32_INIT, pkg, pkgSize);

在做了以上两项修改后,gzip -d不再抱怨了

compress2()生成一个zlib流,它是一个带有zlib头和尾的压缩数据。对于您正在做的事情,您只想要原始的deflate压缩流粘贴到手动生成的gzip头和尾部。

您可以:a)丢弃compress2()输出的前两个和最后四个字节以剥离zlib头和尾部,b)使用deflateInit2(), deflate()deflateEnd()而不是compress2()并选择原始deflate格式,或者c)使用相同的函数而不是选择gzip格式,并摆脱手动构建的gzip头和尾部,因为deflate()将为您这样做。

我推荐c).

相关内容

最新更新