首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >zlib.gzip在不同的OSes上对相同的输入产生不同的结果

zlib.gzip在不同的OSes上对相同的输入产生不同的结果
EN

Stack Overflow用户
提问于 2014-10-22 20:19:07
回答 1查看 1.4K关注 0票数 5

以下代码(在节点js v0.10.28上):

代码语言:javascript
运行
复制
var zlib = require('zlib');
var buf = new Buffer('uncompressed');

zlib.gzip(buf, function (err, result) {
 console.log(result.toString('base64'));
});

生成字符串:

on Win 7 x64:

H4sIAAAAAAAACyvNS87PLShKLS5OTQEA3a5CsQwAAAA=

/T1459.2-1993商品产品的产品、产品、技术、技术等。

on Mac

H4sIAAAAAAAAAyvNS87PLShKLS5OTQEA3a5CsQwAAAA

/T1459.2-1993商品产品的产品、产品、技术、技术等。

(Linux2.6.32-279.19.1.el6.x86_64)

H4sIAAAAAAAAAyvNS87PLShKLS5OTQEA3a5CsQwAAAA=

/T1459.2-1993商品产品的产品、产品、技术、技术等。

似乎他们在结尾的=和第13个字符(C vs A)上有不同,但我不知道为什么。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-10-23 04:45:20

一般差异的一些理论根源

gzip (RFC 1952)采用deflate (RFC 1951)作为压缩格式,技术上只是一种文件格式规范。特别是,算法在选择压缩给出的字节时有很大的自由度(这实际上是一种优势)。

有两个基本的压缩机制可以与deflate一起使用

  • 长度有限的哈夫曼编码:出现频率较高的字符可以被赋予更短的位序列,而较少频繁的字符可以被赋予更长的位序列,从而导致整体上较少的位来表示相同的信息。用于编码的Huffman树可以根据输入(或其中的一部分)动态计算,也可以固定。因此,不同的编码器可能使用不同的Huffman树作为相同的输入,从而导致对树本身和编码字符的不同表示。
  • LZ77压缩:以前输出的子字符串已经不需要再次输出;相反,只需要输出具有相同子字符串长度的反向引用。由于在给定输入中查找所有常见子字符串是一个困难的问题(™),因此使用给定的启发式(例如,跟踪以每个两个字符前缀开头的最后6个子字符串)查找尽可能多的子字符串通常更有效。同样,不同的编码器可以(有效地)为相同的输入产生不同的输出。

最后,所有这些压缩数据都被分散到一个或多个块中,当转换到一个新块时,它由编码器自行决定。理论上,这甚至可以实现每一个字节(尽管这不是真正的压缩!)。当结束一个块时,因为它的内容是使用Huffman位码编码的,所以可能该块不以字节边界结束;在这种情况下,如果流中的后续项必须从整个字节开始(例如,未压缩的块必须从字节边界开始),则可以将任意比特作为填充添加到下一个字节。

因此,正如您所看到的,对于相同的输入,压缩字节有很多不同的方式!即使使用相同的算法(例如,规范的zlib库,不要与同名的RFC (1950)混淆),不同的压缩级别通常也会导致不同的结果。甚至可以想象,同一个程序在同一个环境中运行多次,具有相同的输入和选项,产生不同的结果,例如,由于数据结构命令指针或使用指针作为散列值-指针值可能在执行之间发生变化。而且,多线程实现的本质往往是非确定性的。简而言之,对于给定的输入,您不应该依赖于输出是相同的,除非您使用的实现显式地提供了这种保证。(虽然大多数理智的实现都力求确定性,但在技术上并不是必需的。)

为什么您的特定示例Base64字符串不同

将后面的=符号的差异放在一边,三个示例中有两个具有完全相同的表示形式。这两个字节在第十字节的第一部分中正好相差一位(C -> A) (Base64将三组字节编码为基-64个字符的四重集,因此第13个Base64字符是第十个字节的前六个位)。A代表0,C代表2 -但是请记住,这是字节的高6位,所以它实际上是0和8加上低两位。这些低二位是下一个Base64字符yy的高两位,它以二进制形式表示110010,所以第十字节的低二位是0b11,或者说是3。加起来,第十个字节是一个不同的字节,它的值从一个实现到另一个实现是11,从另一个实现是3。快速查看gzip RFC可以发现,第10字节的表示在其上执行编码的操作系统/文件系统():果然,11被定义为"NTFS文件系统(NT)",3定义为"Unix“。因此,这种情况下的差异完全是因为您在操作系统上执行了编码。(请注意,任何gzip文件的第二个dword都是时间戳,在示例中它被设置为0(没有可用),但在所有三次试验中都可能存在很大的差异,使得差异更难识别。)

至于尾随的=,这只是Base64 64的填充(如在维基百科上解释得很好)。由于Base64使用三个字节组并使用四个字节对它们进行编码,如果编码的字节数不能被三个字节整除,则使用最小的Base64数字数(将输入结束后的字节视为空字节):对于单个字节,只需要两个Base64数字;对于两个字节,只需要三个。=符号只是将Base64数字的整数加到倍数为4;您将注意到,这意味着并不真正需要=符号来解码Base64字符串,因为您知道它的长度(但是如果字符串长度不是4的倍数,则一些Base64解码器会拒绝它)。因此,第二个和第三个示例表示完全相同的字节值,但是由不同的Base64编码器生成的。

就在这儿!我认为我的回答太冗长了,几乎可以归结为一个只有一句话的刁钻的问题,但我忍不住要详细地解释一切:-)

票数 15
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26516369

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档