【问题标题】:How to use miniz to create a compressed file that can be decompressd by gzip?如何使用miniz创建可以被gzip解压的压缩文件?
【发布时间】:2015-08-26 11:14:43
【问题描述】:

我正在 Windows 平台上用 C++ 编写程序。我想压缩一些存储在char[]数组中的数据,并将其输出到一个文件中,稍后我会将文件上传到一个unix服务器,我希望它可以被gzip -d解压。

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

这里是创建gzip文件的代码sn-p:(对不起,我没有把一些变量的定义;它们在别处定义)

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_deflateInit2()MZ_DEFAULT_WINDOW_BITS,这意味着添加zlib页眉和页脚。所以最简单的解决方法是在那里添加一个减号,这样我仍然可以使用compress2() 函数。 (这对我有用,因为我只在一个地方调用这个函数)

其次,正如迈克尔指出的那样,CRC 码应该在未压缩的数据上计算。所以我这样修复它:

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

进行上述两项更改后,gzip -d 不再抱怨了。

【问题讨论】:

  • "CRC32 (CRC-32) 这包含未压缩数据的循环冗余校验值" (source)。在我看来,您正在对 compressed 数据进行 CRC 处理。
  • 谢谢迈克尔,这是我不确定的另一件事,但我确实尝试破解有效 gzip 文件的 CRC 代码并查看错误消息是什么,它是“gzip:无效压缩数据--crc 错误”。所以我相信这不是我问题的根本原因。
  • 嗯,这可能是一件无论如何都需要修复的事情。您如何将数据准确写入文件?您是否在十六进制编辑器中打开了生成的文件并确保它看起来像您期望的那样?您是否将其与使用其他实用程序压缩的文件进行比较?
  • 我使用 ofstream 将其输出到文件中。其实这只是为了测试,真实的场景是通过WinHTTP将它上传到服务器,但这与我的问题无关,所以我没有提到它。我确实尝试过用 gzip 压缩相同的数据,但内容完全不同。由于 miniz 的文档说它与 zlib 兼容,所以我只是假设 compress2() 函数可以给我 gzip 主体,但看起来它没有。所以我想知道我是否正确使用了 miniz 库?还是我错了,有正确答案吗?或者我不能这样使用 miniz?

标签: c++ gzip miniz


【解决方案1】:

compress2() 生成一个 zlib 流,它是使用 zlib 标头和尾标对压缩数据进行压缩。对于您正在做的事情,您只希望原始的 deflate 压缩流粘贴在您手动生成的 gzip 标头和预告片中。

您可以:a) 丢弃 compress2() 输出的前两个和最后四个字节以去除 zlib 标头和尾标,b) 使用 deflateInit2()deflate()deflateEnd() 而不是 @ 987654326@ 并选择原始的 deflate 格式,或者 c) 使用相同的功能,而不是选择 gzip 格式,并摆脱您手动构建的 gzip 标头和尾标,因为 deflate() 会为您做到这一点。

我推荐 c)。

【讨论】:

  • 非常感谢您的解决方案。我不知道我们如何告诉 miniz 使用 gzip 格式,实际上在 miniz 源代码中,有一条评论说它不支持 gzip 标头。您的建议 b) 最适合我,我已更新上述解决方案并接受您的回答。
猜你喜欢
  • 1970-01-01
  • 2017-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多