项目实战——基于LZ77变形和哈夫曼编码的GZIP压缩

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了项目实战——基于LZ77变形和哈夫曼编码的GZIP压缩相关的知识,希望对你有一定的参考价值。

文件压缩:

日常生活中有很多压缩的例子,比如给很长的名字取一个缩写——西安交通大学简称西交大,这样就给我们的生活提供了很大的便捷,那么什么又是文件压缩呢?文件压缩就是将文件通过一些方法变得更小,解压缩就是将文件还原,文件压缩将文件变得更小节省了内存,并且在网络上传输起来也变得很快,还具有一定的保密性,所以这个项目就是为了实现这个目的。


基于哈夫曼树的文件压缩

一、思想:
众所周知在32位平台下一个字节占八个bit位,假如我们文件中的数据是abbbcccccddddddd时,每个字节占用八个比特位,并且有字节重复的问题,这就为给我们提供了压缩的可能性,实际上根本不需要八位的编码我们就足以把a、b、c、d这四个字符区别出来,哈夫曼编码就提供了这样的一种思想——如果能对所有字节找到小于8个比特位的编码,然后用找到的编码对源文件中对应字节重新进行改写,就可以起到压缩源文件的效果,所以,哈夫曼压缩的本质是基于字节层面的压缩
二、步骤
在确定了我们要做什么之后的问题就是如何着手去实现了,分为压缩和解压缩两个部分:
1.压缩:

  • 对于文件的压缩我们之前也提到时要重构文件中出现字符的编码然后重构字节,所以我们要通过哈夫曼树获取字符的哈夫曼编码,首先要将文件中的字符信息统计出来,将字符信息放入哈夫曼树中,包括字符、这个字符在文件中出现的次数(作为哈夫曼树的权值)、字符的编码,我们将这三个信息封装为一个类作为构造哈夫曼树和获取哈夫曼编码的条件。
  • 在压缩文件的开始部分记录源文件的后缀、字符以及字符出现的次数。作用:解压缩重构哈夫曼树的前提。
  • 有了哈夫曼编码作为前提我们就可以对每个字符所对应的字节进行改写了,并将改写后的字节放入到压缩文件中。
    2.解压缩:
  • 读取压缩文件头部所保存的信息——源文件的后缀、源文件中出现的字符以及出现的次数,通过源文件的后缀确定解压缩文件的后缀并打开解压缩文件,通过字符信息重构哈夫曼树。
  • 根据重构的哈夫曼树进行解压缩
    三、源码

    https://github.com/xiangxiangya/no.2/tree/master/Compress/Compress

实战中的问题以及总结:

1.使用优先级队列作为哈夫曼树的底层结构时默认是大堆模式,也就是说此时优先级队列模板的第三个参数是用小于方式去比较的,构建出来的是大堆,堆顶元素是最大的,这与我们想要的结果不符,所以我们要自己写一个比较器,然后当作第三个模板参数传入,默认大堆(小于比较方式)、小堆(大于比较方式)
2.在哈夫曼树我们规定好编码‘0’、‘1’的方向,在叶子节点存放的无疑就是保存进来的字符信息,我们在获取编码的时候采用根节点向上获取编码的方式,此时得到的编码需要逆置才是正确的编码。
3.在压缩文件中需要保存哪些信息?在刚开始的时候我之抓住了压缩字节的特点,于是只将压缩后的数据保存在压缩文件中,但是在解压缩的过程中出现了问题,因为只有压缩数据而没有标准的话是根本无法对信息进行还原的,所以在压缩文件中还需要保存----->1. 源文件的后缀2. 字符次数所占的总行数3. 字符以及字符出现次数 4. 压缩数据。
4.起初在设计时将字符设置为char类型的数据,当源文件中有汉字的时候就产生了访问越界的现象,这是由于对于英文字母来说char就足够用了,而对于汉字来说就需要通过unsigned char来表示,因为unsigned char的取值范围更大。
5.对于大文件的压缩出现了解压缩时不完全的情况,是由于fread函数在文件读取时意外终止,通过查阅资料是由于文件的打开方式不对,在将文件的打开方式改为二进制读或二进制写时就解决了这个问题。

以上是关于项目实战——基于LZ77变形和哈夫曼编码的GZIP压缩的主要内容,如果未能解决你的问题,请参考以下文章

GZIP 与zip区别

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

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

php 压缩函数gzencode gzdeflate gzcompress

数据压缩算法---LZ77算法 的分析与实现

1分钟了解GZIP压缩原理