获取zlib压缩文件的未压缩数据大小?

6
我正在创建一个包含文件上传服务的项目,需要使用zlib的compress()函数压缩数据。我已经将其压缩后通过互联网发送,但是我需要在远程服务器上知道未压缩的文件大小。有没有办法在不先对数据进行uncompress()的情况下找出这些信息,以提高效率?目前我是这样做的,但如果有捷径,我很乐意采用。
顺便问一下,为什么它叫做uncompress?这听起来对我来说相当糟糕,我一直认为它应该是decompress...

1
我猜它被称为uncompress的原因是因为90年代初出现了一个叫做pkzip的程序。还有一个类似的程序叫做pkunzip。我认为“un”一直沿用至今。http://en.wikipedia.org/wiki/PKZIP - gradbot
更多维基百科的研究表明,一场诉讼迫使了名称的更改。"Katz将他的实用程序更名为PKPAK和PKUNPAK。"后来,他们制作了自己的版本,称为zip。"这个名字“zip”(意思是“速度”)是由Katz的朋友Robert Mahoney建议的。他们想暗示他们的产品比当时的ARC和其他压缩格式更快。”因此,zip和unzip应运而生。 - gradbot
3个回答

4

如果您使用原始的“compress”格式上传,则无法获得正在上传的数据大小信息。在这方面,Pax是正确的。
您可以将其存储为压缩缓冲区开头的4字节标头,假设文件大小不超过4GB。
以下是一些C代码示例:

 uint8_t *compressBuffer = calloc(bufsize + sizeof (uLongf), 0);
 uLongf compressedSize = bufsize;
 *((uLongf *)compressBuffer) = filesize;
 compress(compressBuffer + sizeof (uLongf), &compressedSize, sourceBuffer, bufsize);

然后,您发送完整的压缩缓冲区,大小为compressedSize + sizeof (uLongf)。当您在服务器端接收到它时,可以使用以下代码获取数据:

 // data is in compressBuffer, assume you already know compressed size.
 uLongf originalSize = *((uLongf *)compressBuffer);
 uint8_t *realCompressBuffer = compressBuffer + sizeof (uLongf);

如果您不信任客户端发送正确的大小,则需要在服务器上执行某种未压缩数据检查。建议使用uncompress到/dev/null是一个合理的选择。
如果您正在上传.zip文件,则它包含一个目录,告诉您在未压缩时文件的大小。这些信息已经内置于文件格式中,但这也可能受到恶意客户端的影响。

4

我表示怀疑。我不相信底层的zlib库提供了这个功能(虽然我已经有7或8年没有使用过它,但最新的文档似乎并没有表明增加了这个功能)。

一个可能的解决方法是传输另一个文件,其中包含未压缩的大小(例如,同时传输file.zipfile.zip.size),但这似乎充满了危险,特别是如果您错误地计算了大小。

另一种选择是,如果服务器解压缩需要时间但不必立即完成,则在较低优先级的后台任务中执行(如在Linux下使用nice)。但同样,如果大小检查器开始滞后(上传太多),可能会有缺点。

而且我倾向于从“爆炸性解压缩”的角度来考虑解压缩,这不是一个好用的术语 :-)


是的,我可以告诉服务器大小是多少,但用户很容易利用这一点,而且我真的不想做任何复杂的哈希检查之类的事情。 - AriX

3
Zlib格式没有原始输入大小字段,所以我怀疑您将无法在不模拟数据解压的情况下完成此操作。gzip格式有一个“输入大小” (ISIZE) 字段,您可以使用它,但也许您想避免更改压缩格式或要求客户端发送文件大小。但是,即使您使用不同的格式,如果您不信任客户端,仍然需要运行更昂贵的检查,确保未压缩的数据与客户端声称的大小相同。在这种情况下,您可以通过使解压缩到/dev/null的过程变得不那么昂贵来执行此操作,确保zlib不会将输出数据写入任何地方,因为您只想知道未压缩的大小。

谢谢。我没有想到解压到 /dev/null :) - AriX

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接