DEFLATE是同时使用了LZ77算法与哈夫曼编码(Huffman Coding)的一个无损数据压缩算法。它最初是由Phil Katz为他的PKZIP归档工具第二版所定义的,后来定义在RFC 1951规范中。

人们普遍认为DEFLATE不受任何专利所制约,并且在LZW(GIF文件格式使用)相关的专利失效之前,这种格式除了在ZIP文件格式中得到应用之外也在gzip压缩文件以及PNG图像文件中得到了应用。

DEFLATE压缩与解压的源代码可以在自由、通用的压缩库zlib上找到。

更高压缩率的DEFLATE是7-zip所实现的。AdvanceCOMP也使用这种实现,它可以对gzip、PNG、MNG以及ZIP文件进行压缩从而得到比zlib更小的文件大小。在Ken Silverman的KZIP与PNGOUT中使用了一种更加高效同时要求更多用户输入的DEFLATE程序。

压缩算法deflate

gzip,zlib,以及图形格式png,使用的是同一个压缩算法deflate。我们通过对gzip源码的分析来对deflate压缩算法做一个详细的说明。我阅读的gzip版本为 gzip-1.2.4。我们对算法做三种程度的说明。第一种程度,对gzip所使用压缩算法基本原理的说明。第二种程度,对gzip压缩算法实现方法的说明。第三种程度,对gzip实现源码级的说明。
  
  如果你有时间的话,我建议你先不要看下面的内容,自己尝试通过读gzip源码,来了解它的压缩解压缩是如何实现的,这将会是一个非常有趣的智力游戏,千万不要错过。当一个又一个的谜被解开时,那感觉就像唐伯虎同志所说的,“慷慨然诺杯酒中”。(小唐的诗,除了另一个倒霉蛋曹雪芹外,好像不太被人提。)
  
  1 gzip所使用压缩算法的基本原理
  
  gzip 对于要压缩的文件,首先使用lz77算法进行压缩,对得到的结果再使用huffman编码的方法进行压缩。所以我们分别对lz77和huffman编码的原理进行说明。
  
  1.1 ... 1.2 ...
  
  2 gzip压缩算法实现方法
  
  2.1 LZ77算法的gzip实现
  
  首先,gzip 从要压缩的文件中读入64KB的内容到一个叫window的缓冲区中。为了简单起见,我们以32KB以下文件的压缩为例做说明。对于我们这里使用32KB以下文件,gzip将整个文件读入到window缓冲区中。然后使用一个叫strstart的变量在window数组中,从0开始一直向后移动。strstart在每一个位置上,都在它之前的区域中,寻找和当前strstart开始的串的头3个字节匹配的串,并试图从这些匹配串中找到最长的匹配串。
  
  如果当前的strstart开始的串,可以找到最少为3个字节的匹配串的话,当前的strstart开始的匹配长度那么长的串,将会被一个<匹配长度,到匹配串开头的距离>对替换。
  
  如果当前的strstart开始的串,找不到任何的最少为3个字节的匹配串的话,那么当前strstart的所在字节将不作改动。
  
  为了区分是一个<匹配长度,到匹配串开头的距离>对,还是一个没有被改动的字节,还需要为每一个没有被改动的字节或者<匹配长度,到匹配串开头的距离>对,另外再占用一 
  位,来进行区分。这位如果为1,表示是一个<匹配长度,到匹配串开头的距离>对,这位如果为0,表示是一个没有被改动的字节。
  
  现在来说明一下,为什么最小匹配为3个字节。这是由于,gzip 中,<匹配长度,到匹配串开头的距离>对中,"匹配长度"的范围为3-258,也就是256种可能值,需要8bit来保存。"到匹配串开头的距离"的范围为0-32K,需要15bit来保存。所以一个<匹配长度,到匹配串开头的距离>对需要23位,差一位3个字节。如果匹配串小于3个字节的话,使用<匹配长度,到匹配串开头的距离>对进行替换,不但没有压缩,反而还会增大。所以保存<匹配长度,到匹配串开头的距离>对所需要的位数,决定了最小匹配长度至少要为3个字节。
  
  下面我们就来介绍gzip如何实现寻找当前strstart开始的串的最长匹配串。
  
  如果每次为当前串寻找匹配串时,都要和之前的每个串的至少3个字节进行比较的话,那么比较量将是非常非常大的。为了提高比较速度,gzip使用了哈希表。这是gzip实现LZ77的关键。这个哈希表是一个叫head的数组(后面我们将看到为什么这个缓冲区叫head)。gzip对windows中的每个串,使用串的头三个字节,也就是strstart,strstart+1,strstart+2,用一个设计好的哈希函数来进行计算,得到一个插入位置ins_h。也就是用串的头三个字节来确定一个插入位置。然后把串的位置,也就是 strstart的值,保存在head数组的第ins_h项中。我们马上就可以看到为什么要这样做。head数组在没有插入任何值时,全部为0。

当某处的当前串的三个字节确定了一个ins_h,并把当时当前串的位置也就是当时的strstart保存在了head[ins_h]中。之后另一处,当另一处的当前串的头三个字节,再为那三个字节时,再使用那个哈希函数来计算,由于是同样的三个字节,同样的哈希函数,得到的ins_h必然和前面得到的ins_h是相同的。于是就会发现head[ins_h]不为0。这就说明了,有一个头三个字节和自己相同的串把自己的位置保存在了这里,现在head[ins_h]中保存的值,也就是那个串的开始位置,我们就可以找到那个串,那个串至少前3个字节和当前串的前3个字节相同(稍后我们就可以看到这种说法不准确,这里是为了说明方便),我们可以找到那个串,做进一步比较,看到底能有多长的匹配。
  
  我们现在来说明一下,相同的三个字节,通过哈希函数得到的ins_h必然是相同的。而不同的三个字节,通过哈希函数有没有可能得到同一个ins_h,我没有对这个哈希函数做研究,并不清楚,不过一般的哈希函数都是这样的,所以极大可能这里的也会是这种情况,即不同的三个字节,通过哈希函数有可能得到同一个ins_h,不过这并不要紧,我们发现有可能是匹配串之后,还会进行串的比较。
  
  一个文件中,可能有很多个串的头三个字节都是相同的,也就是说他们计算得到的ins_h都是相同的,如何能保证找到他们中的每一个串呢?gzip使用一个链把他们链在一起。gzip每次把当前串的位置插入head的当前串头三个字节算出的ins_h处时,都会首先把原来的head[ins_h]的值,保存到一个叫prev的数组中,保存的位置就在现在的strstart处。这样当以后某处的当前串计算出ins_h,发现head[ins_h]不空时,就可以到prev[ head[ins_h] ]中找到更前一个的头三个字节相同的串的位置。对此我们举例说明。
  
  例,串
  0abcdabceabcfabcg
  ^^^^^^^^^^^^^^^^^
  01234567890123456
  
  整个串被压缩程序处理之后。
  
  由abc算出ins_h。
  这时的head[ins_h]中为 13,即"abcg"的开始位置。
  这时prev[13]中为 9,即"abcfabcg"的开始位置。
  这时prev[9]中为 5,即"abceabcfabcg"的开始位置。
  这时prev[5]中为 1,即"abcdabceabcfabcg"的开始位置。
  这时prev[1]中为 0。
  
  我们看到所有头三个字母为abc的串,被链在了一起,从head可以一直找下去,直到找到0。
  
  现在我们也就知道了,三个字节通过哈希函数计算得到同一ins_h的所有的串被链在了一起,head[ins_h]为链头,prev数组中放着的更早的串。这也就是head和prev名称的由 
  来。
  
  gzip寻找匹配串的另外一个值得注意的实现是,延迟匹配。会进行两次尝试。比如当前串为str,那么str发生匹配以后,并不发生压缩,还会对str+1串进行匹配,然后看哪种 
  匹配效果好。
  
  例子 ...
从这个例子中我们就看到了做另外一次尝试的原因。如果碰到的一个匹配就使用了的话,可能错过更长匹配的机会。现在做两次会有所改善。
  
  ...
  
  2.2 问题讨论
  
  我在这里对gzip压缩算法做出了一些说明,是希望可以和对gzip或者压缩解压缩感兴趣的朋友进行交流。
  我对gzip的了解要比这里说的更多一些,也有更多的例子。如果哪位朋友愿意对下面的问题进行研究,以及其他压缩解压缩的问题进行研究,来这里http://jiurl.cosoft.org.cn/forum/ 和我交流的话,我也愿意就我知道的内容进行更多的说明。
  
  下面是几个问题
  
  这种匹配算法,即用3个字节(最小匹配)来计算一个整数,是否比用串比较来得高效,高效到什么程度。
  
  哈希函数的讨论。不同的三个字节,是否可能得到同一个ins_h。ins_h和计算它的三个字节的关系。
  
  几次延迟尝试比较好?
  
  用延迟,两次尝试是否对压缩率的改善是非常有限的?
  
  影响lz77压缩率的因素。
  
  压缩的极限。
    
  2.3 ...
  
  3 gzip源码分析
  
  main() 中调用函数 treat_file() 。
  treat_file() 中打开文件,调用函数 zip()。注意这里的 work 的用法,这是一个函数指针。
  zip() 中输出gzip文件格式的头,调用 bi_init,ct_init,lm_init,
  其中在lm_init中将 head 初始化清0。初始化strstart为0。从文件中读入64KB的内容到window缓冲区中。
  由于计算strstart=0时的ins_h,需要0,1,2这三个字节和哈希函数发生关系,所以在lm_init中,预读0,1两个字节,并和哈希函数发生关系。
  
  然后lm_init调用 deflate()。
  deflate() gzip的LZ77的实现主要deflate()中。
  ...

来自: http://hi.baidu.com/%CD%BC%BA%BC%BF%C6%BC%BC/blog/item/b2d1731812146eb34bedbc5b.html

DEFLATE 压缩算法相关推荐

  1. 文章分享:Gzip 格式和 DEFLATE 压缩算法详解

    Introduction 引言: 当键入 tar -zcf src.tar.gz src 时,就可以将 src 下的所有文件打包成一个 tar.gz 格式的压缩包.这里的 "tar" ...

  2. GZip、Deflate压缩算法对应的C#压缩解压函数

    GZip解压函数 View Code GZip压缩函数 View Code 1 /// <summary> 2 /// GZip压缩函数 3 /// </summary> 4 ...

  3. Zlib压缩算法:LZ77、LZ78、霍夫曼编码、滑动窗口、Rabin-Karp算法、哈希链、I/O缓冲区

    Table of Contents 1.简介 1.1 什么是zlib 2.压缩算法 2.1 放气 2.2 LZ77 2.2.1 滑动窗口 2.2.2 长距离对 2.3 霍夫曼编码 3. zlib的实现 ...

  4. 常用无损压缩算法原理简析

    无损压缩算法原理 压缩一般分为两个步骤,建模和编码.一个完美的模型可以描述数据流是如何产生的,相当于一个python类里面的generator.只需要这个generator就可以产生所有数据,从而大大 ...

  5. Gzip Zlib PNG 压缩算法【转】

    gzip,zlib,以及图形格式png,使用的是同一个压缩算法deflate.我们通过对gzip源码的分析来对deflate压缩算法做一个详细的说明.我阅读的gzip版本为 gzip-1.2.4.我们 ...

  6. 数据流压缩原理实现(huffman编码,LZ77压缩算法)

    1. 压缩原理deflate算法 a) LZ77 算法原理 b) Huffman算法原理 c) Huffman算法测试实例 2.  关于zlib库的实际应用以及gzip格式分析查看下一篇 一.数据压缩 ...

  7. zlib-Deflate压缩算法

    写在前边 最近在做一些关于网络优化的一些事情,涉及到对纯数据(Data.字符串.Json等)进行压缩,用到了Deflate压缩算法,这里就简单说一下如何用OC实现 Deflate 先看代码 (后面会给 ...

  8. 爬取B站弹幕(Java版本,附带deflate解压)

    前几天突发奇想要爬取B站的弹幕,于是简单在网上找到了B站的弹幕API,关于如何获取B站的接口这里不再赘述,本文主要集中解决我在此开发过程中所遇到的难题.(采用okhttp) 开始的时候,我是想直接爬取 ...

  9. gzip, png的压缩算法lz77

    gzip,zlib,以及图形格式png,使用的是同一个压缩算法deflate.我们通过对gzip源码的分析来对deflate压缩算法做一个详细的说明.我阅读的gzip版本为 gzip-1.2.4.我们 ...

  10. 从 Gzip 压缩 SVG 说起 — 论如何减小资源文件的大小

    原文地址:Of SVG, Minification and Gzip 原文作者:Anton Khlynovskiy 译文出自:掘金翻译计划 本文永久链接:github.com/xitu/gold-m- ...

最新文章

  1. Hadoop 学习笔记 (十一) MapReduce 求平均成绩
  2. 使用Nomad和OpenFaaS提供FaaS服务
  3. Android开发之高德API篇:2、高德API线路规划
  4. OpenJudge NOI 1.5 02:财务管理
  5. Rabbitmq的原生javaAPI讲解
  6. iOS-仿智联字符图片验证码
  7. Ubuntu14.04server 安装 fping
  8. TTS之训练vocoder
  9. 7-1 近似求PI (15 分)
  10. android+嵌入地图,Android 给app加入百度地图
  11. 顺德苹果售后维修体验
  12. 淘特,阿里在下沉市场的一把好刀
  13. Java 集合之TreeSet 自定义类 比较器
  14. 能用“收款人支付手续费”戏弄骗子吗?
  15. android pc模拟器哪个好用,电脑手游安卓模拟器哪个好用流畅 好用的安卓模拟器...
  16. clickhouse UI可视化工具
  17. 文樾杰出五金交电进销存管理系统 v6.12 下载
  18. php制作万年历的步骤_PHP制作万年历
  19. i3-10110U和i5 1035g7 哪个好
  20. 如何在阿里云服务器构建discuz论坛(快速lamp架构)

热门文章

  1. LIS3DH 三轴加速度传感器使用流程及示例
  2. 使用LIS2DH12三轴加速度传感器检测震动与倾斜角度
  3. monkey命令——压力测试——个人总结
  4. 物理卷、卷组与逻辑卷的关系及相关操作详述
  5. 在图形用户登录界面输入正确用户名与密码后,闪了一下(即将要登录进去那一刹那),它NND给我蹦出来了!
  6. 发布一个水管接通游戏的源代码
  7. 拥有70多个名字的南京,改城市名就像改微信名一样
  8. python判断英文字母_python判断字符串中是否含有英文 | 张先生博客
  9. 中国大学慕课公开课-《视听语言》-学习笔记-1
  10. 小学生课外必读书目(推荐)