Mrc*_*ief 2 javascript operating-system node.js
以下代码(在 node js v0.10.28 上):
var zlib = require('zlib');
var buf = new Buffer('uncompressed');
zlib.gzip(buf, function (err, result) {
console.log(result.toString('base64'));
});
Run Code Online (Sandbox Code Playgroud)
产生字符串:
在 Win 7 x64 上:
H4sIAAAAAAAACyvNS87PLShKLS5OTQEA3a5CsQwAAAA=
^ ^
在 Mac 上
H4sIAAAAAAAAAyvNS87PLShKLS5OTQEA3a5CsQwAAAA
^ ^
CentOs (Linux 2.6.32-279.19.1.el6.x86_64)
H4sIAAAAAAAAAyvNS87PLShKLS5OTQEA3a5CsQwAAAA=
^ ^
似乎他们在结尾=和第 13 个字符(Cvs A)上有所不同,但我不确定为什么。
gzip( RFC 1952 ) 使用deflate( RFC 1951 ) 作为其压缩格式,在技术上只是一种文件格式规范。特别是,算法在选择压缩给定字节的方式上有很大的自由度(这实际上是一种优势)。
有两种基本的压缩机制可以用于deflate:
长度受限的霍夫曼编码:可以为出现频率较高的字符提供较短的位序列,而可以为出现频率较低的字符提供较长的位序列,从而导致表示相同信息的总体位更少。用于编码的哈夫曼树可以根据输入(或其中的一部分)动态计算,也可以是固定的。结果,不同的编码器可能对相同的输入使用不同的霍夫曼树,导致树本身和编码字符的不同表示。
LZ77压缩:已经输出的子串不需要再次输出;相反,只需要输出具有相同子串长度的反向引用。由于在给定输入中查找所有公共子字符串是一个困难问题™,因此使用给定启发式查找尽可能多的子字符串通常会更有效(例如跟踪以每个两个字符前缀开头的最后 6 个子字符串)。同样,不同的编码器可以(有效地)为相同的输入产生不同的输出。
最后,所有这些压缩数据都分散到一个或多个块中,何时切换到新块由编码器决定。从理论上讲,这甚至可以在每个字节中完成(尽管这并不是真正的压缩!)。结束一个块时,因为它的内容是使用霍夫曼位码编码的,所以该块可能不会以字节边界结束;在这种情况下,如果流中的后续项必须从整个字节开始(例如,未压缩的块必须从字节边界开始),则可以添加任意位作为填充以舍入到下一个字节。
如您所见,相同输入的压缩字节可能有多种不同!即使使用相同的算法(例如规范的zlib 库,不要与同名的RFC(1950)混淆),不同的压缩级别通常会导致不同的结果。甚至可以想象,同一个程序在具有相同输入和选项的同一个环境中多次运行会产生不同的结果,例如,由于数据结构对指针进行排序或使用指针作为散列值——指针值可以在执行之间改变。此外,多线程实现的性质往往是不确定的。简而言之,您不应依赖于给定输入的输出是否相同,除非您使用的实现明确提供了该保证。(尽管大多数理智的实现都力求确定性,但这在技术上不是必需的。)
撇开尾随=符号的差异一分钟,您的三个示例中的两个具有完全相同的表示。这两个在第十个字节的第一部分仅相差一位 ( C-> A)(Base64 将字节的三元组编码为 base-64 字符的四元组,因此第十三个 Base64 字符是第十个字节的前六位)。A代表 0,并C代表2——但请记住,这是字节的高六位,所以它实际上是 0 和 8 加上低两位。那低两位是下一个Base64字符的高两位,y:y代表50,是110010二进制的,所以第十个字节的低两位是0b11, 或 3. 将它们放在一起,第 10 个字节是不同的,它的值是 11 来自一个实现,而 3 来自另一个。快速查看gzipRFC 会发现,第十个字节表示执行编码的操作系统/文件系统:果然,11 被定义为“NTFS 文件系统 (NT)”,3 被定义为“Unix”。因此,这种情况下的差异完全取决于您执行编码的操作系统。(请注意,任何gzip文件的第二个 dword都是时间戳,在您的示例中设置为 0(无可用),但在所有三个试验中很容易出现巨大差异,从而难以发现差异。)
至于尾随=,那只是 Base64 的填充(正如在 Wikipedia 上很好地解释的那样)。由于 Base64 以三个字节为一组并使用四个字节对其进行编码,如果编码的字节数不能被 3 整除,则使用最少的 Base64 位数(将输入末尾的字节视为空字节):对于单个字节,只需要两个 Base64 数字;对于两个,只需要三个。这些=符号只是为了将 Base64 数字的数量四舍五入为四的倍数;你会注意到这意味着=解码 Base64 字符串并不真正需要符号,因为您知道它的长度(但如果字符串不是 4 的倍数,一些 Base64 解码器将拒绝该字符串)。因此,您的第二个和第三个示例表示完全相同的字节值,但由不同的 Base64 编码器生成。
你有它!我认为我的回答过于冗长,几乎可以归结为一个用一句话回答的技巧问题,但我无法抗拒详细解释所有内容:-)
| 归档时间: |
|
| 查看次数: |
1053 次 |
| 最近记录: |