DEFLATE压缩数据格式规范 v1.3

原版文档,及官方代码库实现,可以从zlib官网下载获取。

备忘录状态

这个备忘录为互联网社区提供的信息。这个备忘录未指定任何形式的互联网标准。这个备忘录的分发是不受限制的。

IESG注:

IESG 对本文档中包含的任何知识产权声明的有效性不持任何立场。

注意

Copyright 1996 L. Peter Deutsch
允许出于任何目的的免费复制和分发本文档,包括翻译为其他语言,但需要提供版权声明,并且该通知需要保留,对原始文档中任何实际的改变和删除也需明确标记。
可以在ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html获取该文档及相关文档的最新版本。

摘要

该规范定义了一种无损数据压缩格式,该格式使用LZ77算法和霍夫曼编码组合进行数据压缩,其效率可以和目前可用的最佳通用软件相比较。对于连续任意长的数据,可以仅使用部分前部数据进行数据的产生和使用。该格式可以以专利未涵盖的方式实施。

1、介绍

1.1 目的

本规范的目的是定义一种无损压缩数据格式:

  • 独立与CPU类型,操作系统,文件系统和字符集,可以互换使用;
  • 对于任意长度的顺序输入数据流,使用有限数量的中间存储,也可以 进行生成或使用,并且可以在数据通信中或类似结构中使用,如Unix过滤器。
  • 压缩数据的效率可媲美当前最佳的通用压缩方法,尤其比“压缩”程序好得多;
  • 可以以专利未涵盖的方式轻松实施,因此可以自由实践;
  • 与当前广泛使用的gzip实用工具生成的文件格式兼容,解压缩器将能够读取现有gzip压缩器产生的数据。
    本规范定义的数据格式不支持:
  • 随机访问压缩数据;
  • 当前可用的压缩专用数据(例如,光栅图形)的最佳专用算法。
    Asimple计数参数表明,无损压缩算法无法压缩每个可能的输入数据集。 对于此处定义的格式,最坏的情况是每32K字节块扩展5个字节,即对于大型数据集,大小增加0.015%。 英文文本通常压缩2.5到3倍; 可执行文件文件压缩率通常略低; 诸如光栅图像之类的图形数据可能会压缩得更多。
1.2 目标受众

该规范旨在供软件的实现者用于将数据压缩为“deflate”格式或从“deflate”格式解压缩数据。
这个规范的文本假定在位和其他原始级别的编程方面具有基本的背景知识数据表示。 熟悉霍夫曼编码技术很有帮助,但不是必需的 。

1.3 范围

该规范指定了一种方法,用于将字节序列表示为(通常较短的)比特位序列,以及将后一个比特位序列打包为字节的方法。

1.4 遵守

除非以下另有说明,否则兼容的解压缩器必须能够接受和解压缩任何符合此处介绍的所有规格设置的数据;符合标准的压缩机必须产生符合此处介绍的所有规格数据集。

1.5 所用术语和惯例定义

Byte:以一个单位存储或传输的8位(与八位位组相同)。 在本规范中,一个字节正好是8位,即使在将字符存储在不同于八位的位数上的机器上也是如此。 参见下面的编号字节内的位的数量。
String:任意字节序列。

1.6 相对旧版本的修改

自从本规范的1.1版以来,对deflate格式没有任何技术更改。 在版本中1.2,某些术语已更改。 版本1.3是规范到RFC样式的转换。

2 压缩表示概述

一个压缩数据集是由一系列的关于输入数据的连续块组成。这些块的大小是任意的,除了不可压缩的块被限制为65535字节。
每一个被压缩的块使用LZ77算法和Huffman编码的组合。每个块的Huffman树是独立与先前或后续块的树;LZ77算法可能会使用前一个块中出现的重复字符串的引用,最大为32K的输入数据。
每个块由两部分组成:一部分为描述压缩数据组成部分和压缩数据的Huffman树;(Huffman树本身使用了Huffman压缩编码。)压缩数据由一系列的两种类型元素组成:文本字节(之前32K输入字节中未检测到重复的字符串),和指向重复字符串的指针,这个指针内容表示为一对<长度,后向距离>。“deflate”格式表示限制了32K的距离,和258字节的长度,但是并未限制块的大小,除了不可压缩块(如上所述)受到限制外。
在使用Huffman编码的压缩数据中每种类型的值(文本,距离和长度)代码,使用一个代码树表示文件和长度,并且使用单独的代码树表示距离。每个块的代码树以紧凑的形式出现在该块的压缩数据之前。

3 详细规范

3.1 总体惯例

在下图中,这样的框:
在这里插入图片描述
表示一个字节;这样的一个框:
在这里插入图片描述
表示一定数目的字节。
存储在计算机中的字节没有“位顺序”,因为它们始终被视为一个单位。然而,一个视为0到255之间的整数的字节确实具有最高和最低有效位,并且我们在左侧写最高有效位的数字,我们也在左侧写最高有效位的bit。在下图中,我们对字节的位进行编号,为了位0是最低有效位,即位的编号:
在这里插入图片描述
在计算机中,一个数字可能由多个字节组成。所有多字节数字的描述格式,都是先以最低有效字节存储(在较低的存储器地址处)。例如,数字520的存储为:
在这里插入图片描述

3.1.1 打包为字节

该文档并没有解决字节的比特按比特序传输顺序的问题,因为描述的最终数据格式是以字节导向的,而不是位导向的。但是我们下面的描述压缩块格式,是各种比特长度的数据元素序列,而不是字节序列。因此我们必须指定如何将这些数据元素打包为字节以形成最终的压缩字节序列:

  • 数据元素按字节内比特数递增的顺序打包到字节中,即从字节的最低有效位开始。
  • 除Huffman编码以外的数据元素均已数据的最低有效位开始打包。
  • Huffman编码从编码的最高有效位开始打包。
    换句话说,如果要以字节序列的形式打印压缩数据,则由“right”边距处的第一个字节开始继续到“left”,和通常一样每个字节的最高有效位在左边,可以在正确大小端序列和反转的Huffman编码序中用固定宽度的元素从右向左的正确解析结果(即编码的第一位是在LSB的位置)。
3.2 压缩块格式
3.2.1 前缀和Huffman编码的概要

前缀编码通过比特序列(代码)表示来自先验已知字母的符号,每一个符号对应一个代码,使得不同符号可以由不同长度的比特序列表示,但是解析器使用可以逐个符号明确的解析编码的字符串。
当我们以二叉树的形式定义了前缀代码,其中从每个非叶子节点的两个边沿标记为0和1,并且其中的叶节点标识(标签上)和符号一一对应;那么符号的代码时从根部开始到标有该符号的叶子上边沿0和1的序列。例如:
在这里插入图片描述
解析器可以通过从根目录向下遍历树来解码编码输入流中的下个符号,在每个步骤中,选择与下一个输入位相对应的边沿。
给定具有已知符号频率的字符,Huffman编码允许构造一个最佳的前缀代码(对那些具有符号频率的字符串中的任何符号使用最少的位代表该字母可能的前缀代码)。这样的编码成为Huffman编码。(请参见本章5中的参考文献[1],有关霍夫曼代码的更多信息的参考。)
请注意,在“deflate”格式中,各种字母的Huffman编码不得超过一定的最大的代码长度。该约束适用于从符号频率计算代码长度的算法复杂化。同样,有关详细信息,请参考第5章。

3.2.2 使用deflate格式的Huffman编码

每个字母以“deflate”格式使用的Huffman编码有两个附加规则:

  • 对于给定比特长度的所有代码在字典上有连续的值,与它们代表的符号具有相同的顺序;
  • 在字典上,较短的代码在较长的代码之前。
    我们可以重新编码上面的示例以遵循以下规则,假设字母顺序为ABCD:
    在这里插入图片描述

即,0在10之前,且在11x之前,而110和111在字典上是连续的。
给定此规则,我们只需给出代码的位长即可依次按字母的每个符号定义一个字母的Huffman代码;这足以确定实际代码。在我们示例中,代码完成由位长的顺序(2,1,3,3)定义。以下算法生成编码为整数,旨在从最高有效位读取到最低有效位。这个编码的长度被初始化在tree[I].Len,编码在tree[I].Code中生成。
1)计算每个代码长度的代码数量。 令bl_count [N]为长度为N,N >= 1。
2) 找到每个代码长度的最小代码的数值:
在这里插入图片描述
3)使用相同长度的所有代码的连续值,将数值分配给所有代码在第2步确定的基本值。从未使用过的代码(位长度为零)一定不会分配一个值。
在这里插入图片描述
例如:
考虑字母ABCDEFGH,其位长度为(3、3、3、3、3、2、4、4)。 步骤1之后,我们将:
在这里插入图片描述
步骤2计算以下接下来的next_code值:
在这里插入图片描述
步骤3生成以下代码值:
在这里插入图片描述

3.2.3 块格式的细节

每个压缩数据块均以包含以下数据的3个标头位开始:

  • first bits: BFINAL
  • next 2 bits: BTYPE

请注意,标头位不一定在字节边界处开始,因为块不一定占用整数字节。
BFINAL在数据集的最后一块时被设置。
BTYPE指定了如何压缩数据,如下所示:

  • 00 - no compression
  • 01 - compressed with fixed Huffman codes
  • 10 - compressed with dynamic Huffman codes
  • 11 - reserved(error)

两种压缩情况之间的唯一区别是Huffman编码的文字/长度和被定义的距离字母。
在所有情况下,实际数据的解码算法如下:
在这里插入图片描述
注意,重复的字符串引用可能引用前一个块种的字符串。即后退距离可能跨越一个或多个块的边界。但是距离不能超过输出流的起点。(假设预设字典的应用程序可能会丢弃输出流的一部分;距离可以参考输出流部分)也要注意引用的字符串可能与当前位置重叠;例如,如果解码的最后两个字节的值分别为X和Y,则字符串引用< length = 5,distance = 2>将添加到X,Y,X,Y,X的输出流中。

3.2.4 无压缩块(BTYPE=00)

到下一个字节边界前的任何输入位都将被忽略。 该块的其余部分包括以下内容信息:
在这里插入图片描述

LEN是块中数据字节的数量。 NLEN是LEN的补充。

3.2.5 压缩块(长度和距离编码)

如上所述,“deflate”格式的编码数据块由三个不同概念的字母组成:从字节值(0…255)的字母开始的文本,或<length, backward distance>对,其中从(3…258)绘制length,从(1…32768)绘制distance。实际上,文本和长度字母合并为一个字母(0…285),其中值0…255表示文本字节,值256表示块结束,值257…285表示长度代码(可能与符号代码后面的额外位结合使用),如下所示:
在这里插入图片描述
多余的位应解释为以最高有效位在前的方式存储的机器整数,例如1110代表值14。
在这里插入图片描述

3.2.6 固定Huffman编码压缩(BTYPE=01)

对于两个字母的Huffman编码是固定的,并且在数据中未明确表示。 Huffman文字/长度字母的代码长度为:
在这里插入图片描述
如上所述,代码长度足以生成实际代码。我们在使用表格展示以提高清晰度。文本/长度值286-857永远不会真正出现在压缩数据中,但是会参与代码的构建。
距离代码0-31由(固定固定)5位代码表示,可能的附加位在上面第3.2.5章节的表格中展示。请注意,距离代码30-31实际不会在压缩数据中。

3.2.7 动态Huffman编码压缩(BTYPE=10)

对于出现两个字母的Huffman编码出现在标题头之后和实际压缩数据之前,首先是文字/长度代码,然后是距离代码。每个代码被代码长度序列定义,如上面第3.2.2章节所述。为了更加紧凑,使用Huffman编码对码长序列本身进行压缩。代码长度的表示字母如下所示:
在这里插入图片描述码上为0表示文本/长度或距离字母中对应符号不会出现在当前块中,并且不应该参与前面给出的Huffman编码构造算法。如果仅使用一个距离码,它是使用1bit而不是0bit编码;在这种情况下,只有一个代码长度为1,带有一个未使用的代码。一个0bit的距离代码表示没有距离代码(数据全部为文字)。
现在我们能够定义块的格式:
在这里插入图片描述
这个重复码的代码长度为从HLIT + 257到HDIST + 1。 换句话说,所有单个序列的代码长度值为HLIT + HDIST + 258。

3.3 遵守

压缩器可能会进一步限制上一节指定的值范围,但仍然符合要求;例如,它也许将后向指针的范围限制为小于32K的某个值。同样,压缩程序可能会限制块的大小,以便可压缩的块适合内存。
一个兼容的解压缩器必须能够接受上一节中定义的所有可能值,并且必须能接受任意大小的块。

4 压缩算法细节

尽管本文档旨在定义“deflate”压缩数据格式,但不引用任何与LZ77产生压缩格式相关的特定压缩算法(Lempel-Ziv 1977,参见下面的参考文献[2]);由于LZ77的许多变体都已申请专利,因此强烈建议解压缩器的实现者使用此处介绍的一般算法,这是已知不会申请专利的。本节材料本身不是规范定义的一部分,并且压缩器不需要为了合规而遵循它。
当压缩器开始使用一个新的树开始新的块时,或当前块占满了压缩程序的块缓存区时,压缩器将终止当前的块。
压缩器使用3个字节序列的链式哈希表来查找重复的字符串。在压缩期间的任何给定点,接下来输入的3个字节XYZ需要被检查(当前不一定全部都不同)。首先,压缩程序检查XYZ的哈希链。如果这个链是空的,则压缩程序仅将X作为文字字节写出,并且在输入中前进一个字节。如果这个哈希链不为空,表示序列XYZ(或者,如果不幸,另外一些3个字节具有相同的哈希函数值)最近存在,压缩程序会将XYZ哈希链上的所有字符串与从当前点开始的实际输入数据序列进行比较,选择最长的匹配项。
压缩程序从最近的字符串开始搜索哈希链,以支持最小的距离和使用Huffman编码。哈希链是单个链接。没有从哈希链中删除;该算法只是丢弃太旧的匹配项。为了避免最坏情况,非常长的哈希链会以运行时参数确定的特定长度任意截断。
为了提高整体压缩率,压缩程序可以选择推迟匹配项的选择(lay matching):在找到长度为N的匹配项后,压缩器会从该位置开始从后续输入数据中搜索更长的匹配项。如果发现更长的匹配项,则会将前一个匹配项的长度截短为1(从而产生单字节文本),然后发出更长的匹配。否则,它将发出原始匹配,并且,如上描述,在继续操作之前先前进N个字节。
运行时参数也控制着“lazy match”过程。如果压缩比更重要,则压缩程序会尝试进行完整的第二次搜索,而不管第一次匹配的长度如何。在正常情况下,如果当前匹配时“足够长”,压缩程序会减少对更长匹配的搜索,从而加快整个过程。如果速度是最重要的,则压缩程序仅在没有匹配被发现时将新字符串插入哈希表,或者匹配项不是“太长”。这降低了压缩率,但是节省了时间,因为插入次数和搜索次数都减少了。

5 引用

[1] Huffman, D. A., “A Method for the Construction of Minimum Redundancy Codes”, Proceedings of the Institute of Radio Engineers, September 1952, Volume 40, Number 9, pp. 1098-1101.
[2] Ziv J., Lempel A., “A Universal Algorithm for Sequential Data Compression”, IEEE Transactions on Information Theory, Vol. 23, No. 3, pp. 337-343.
[3] Gailly, J.-L., and Adler,M., ZLIB documentation and sources, available in ftp://ftp.uu.net/pub/archiving/zip/doc/
[4] Gailly, J.-L., and Adler, M., GZIP documentation and sources, available as gzip-*.tar in ftp://prep.ai.mit.edu/pub/gnu/
[5] Schwartz, E. S., and Kallick, B. “Generating a canonical prefix encoding.” Comm. ACM, 7,3 (Mar.1964), pp. 166-169.
[6] Hirschberg and Lelewer, “Efficient decoding of prefix codes,” Comm. ACM, 33,4, April 1990, pp. 449-459.

6 安全注意事项

任何数据压缩方法都涉及减少数据冗余。 因此,任何损坏的数据可能会产生严重影响,并且难以纠正。 另一方面,未压缩的文本尽管存在一些损坏的字节,但可能仍然可读。
建议使用此数据格式的系统提供一些方法来验证数据完整性。 例如,参见参考文献[3]。

7 源码

符合“ deflate”的压缩器和解压缩器的C语言实现的源代码位于ftp://ftp.uu.net/pub/archiving/zip/zlib/的zlib软件包中。

8 致谢

本文档中引用的商标是其各自所有者的财产。
Phil Katz设计了deflate格式。 Jean-LoupGailly和Mark Adler编写了本规范的相关软件。 Glenn Randers-Pehrson将此文档转换为RFC和HTML格式。

9 作者地址

L. Peter Deutsch

  • Aladdin Enterprises
  • 203 Santa Margarita Ave.
  • Menlo Park, CA 94025
  • Phone: (415) 322-0103 (AM only)
  • FAX: (415) 322-1734
  • EMail: ghost@aladdin.com

Questions about the technical content of this specification can be sent by email to:

Editorial comments on this specification can be sent by email to:

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值