项目——文件压缩

一、简历上写的

测试用例:77M大小的一个文本文件

压缩:  33秒

解压缩: 6秒

文件压缩

项目简介: 对文件进行无损压缩,节省空间,用在网络传输中,节省流量传输宽带

开发环境: Linux/Windows,C++,VS2013,vim,gdb,g++,make

主要技术: HuffmanTree,Heap,字符串操作,位操作

项目描述: 压缩,解压缩过程及原理

压缩:读取待压缩文件中字符出现次数,使用贪心算法建立HuffmanTree

每个字符都有一串对应Huffman编码,出现频率高的字符编码短,反之则长,达到文件压缩目的

将每个字符对应的编码转换成对应的二进制位表示并写入压缩文件

将对应字符及对应字符出现次数写入配置文件,方便解压缩时重建HuffmanTree

解压缩:根据配置文件重建HuffmanTree

读取压缩文件,解析二进制位,对应在HuffmanTree中解析出对应的字符,还原文件内容

代码托管: https://github.com/18392517817/_DataStruct_/tree/master/FileCompress

二、你这个文件压缩工具是怎么实现的?为什么要实现这个工具?

(1)、为什么要实现这个文件压缩?

压缩软件是为了解决早期计算机储存空间不足而设计的。文件被压缩后使用的储存空间会较少。同时压缩后文件编码被改变,就不能对原文件进行编辑,更改,所以压缩软件都有解压缩功能,即将文件恢复成原来的样子。

但它还有两项用途:

一,对于网管:减少网站使用的储存空间,服务器的空间是付费的。

二,对于个人:简单的文件加密。

目前互联网络上大家常用的FTP文件服务器上的文件大多属于压缩文件,文件下载后必须先解压缩才能够使用;另外在使用电子邮件附加文件功能的时候,最好也能事先对附加文件进行压缩处理。这样做的结果,除了减轻网络的负荷,更能省时省钱。

目前网络上有两种常见的压缩格式:一种是Zip,另一种是EXE。其中Zip的压缩文件可以通过WinZip这套解压缩工具进行解压缩,而EXE则是属于自解压文件,只要用鼠标双击这类下载后的文件图标,便可以自动解压缩。因为EXE文件内含解压缩程序,因此会比Zip略大一些。若想充分考虑到文件容量的大小,其实Zip是一个较佳的选择

(2)、文件压缩实现的思路:

我们把文件中一定位长的值看作是符号,比如把8位长的256种值,也就是字节的256种值看作是符号。我们根据这些符号在文件中出现的频率,对这些符号重新编码。对于出现次数非常多的,我们用较少的位来表示,对于出现次数非常少的,我们用较多的位来表示。这样一来,文件的一些部分位数变少了,一些部分位数变多了,由于变小的部分比变大的部分多,所以整个文件的大小还是会减小,所以文件得到了压缩。

具体步骤:

第一步:

要进行Huffman编码,首先要把整个文件读一遍,在读的过程中,统计每个符号的出现次数(我们把字节的256种值看作是256种符号)。然后根据符号的出现次数,建立Huffman树,通过Huffman树得到每个符号的新的编码。对于文件中出现次数较多的符号,它的Huffman编码的位数比较少。对于文件中出现次数较少的符号,它的Huffman编码的位数比较多。然后把文件中的每个字节替换成他们新的编码。

第二步:建立Huffman树

1、把所有符号看成是一个结点,并且该结点的值为它的出现次数。进一步把这些结点看成是只有一个结点的树。

2、每次从所有树中找出值最小的两个树,为这两个树建立一个父结点,然后这两个树和它们的父结点组成一个新的树,这个新的树的值为它的两个子树的值的和。如此往复,直到最后所有的树变成了一棵树。我们就得到了一棵Huffman树。

3、通过Huffman树得到Huffman编码:

这棵Huffman树,是一棵二叉树,它的所有叶子结点就是所有的符号,它的中间结点是在产生Huffman树的过程中不断建立的。我们在Huffman树的所有父结点到它的左子结点的路径上标上0,右子结点的路径上标上1。

4、现在我们从根节点开始,到所有叶子结点的路径,就是一个0和1的序列。我们用根结点到一个叶子结点路径上的0和1的序列,作为这个叶子结点的Huffman编码。

第三步:保存配置文件

为了在解压缩的时候,得到压缩时所使用的Huffman树,我们需要在压缩文件中,保存树的信息,也就是保存每个符号的出现次数的信息。

总结:

1、我们可以看到,Huffman树的建立方法就保证了,出现次数多的符号,得到的Huffman编码位数少,出现次数少的符号,得到的Huffman编码位数多。

各个符号的Huffman编码的长度不一,也就是变长编码。对于变长编码,可能会遇到一个问题,就是重新编码的文件中可能会无法如区分这些编码。

比如,a的编码为000,b的编码为0001,c的编码为1,那么当遇到0001时,就不知道0001代表ac,还是代表b。出现这种问题的原因是a的编码是b的编码的前缀。

由于Huffman编码为根结点到叶子结点路径上的0和1的序列,而一个叶子结点的路径不可能是另一个叶子结点路径的前缀,所以一个Huffman编码不可能为另一个Huffman编码的前缀,这就保证了Huffman编码是可以区分的。

2、压缩:

读文件,统计每个符号的出现次数。根据每个符号的出现次数,建立Huffman树,得到每个符号的Huffman编码。将每个符号的出现次数的信息保存在压缩文件中,将文件中的每个符号替换成它的Huffman编码,并输出。

3、解压缩:

得到保存在压缩文件中的,每个符号的出现次数的信息。根据每个符号的出现次数,建立Huffman树,得到每个符号的Huffman编码。将压缩文件中的每个Huffman编码替换成它对应的符号,并输出。

三、分析一下你的Huffman树的压缩算法的适用范围?以及你的huffman压缩工具的优缺点?

在压缩文件的时候,人们不禁会产生一些新想法或者遇到一些疑问:

1、是否可以对压缩后的数据再次压缩?

答:就操作上来说,当然能反复编码,但通过对本文例子中得到的新编码再次操作后会发现,结果是不会有任何变化的。压缩的实质,在于消除特定字符分布上的不均衡,通过将短码分配给高频字符,而长码对应低频字符实现长度上的优化。而数据经过一次压缩后,字符的分布已经几乎平均化了,很难更进一步的压缩了。

2、当2 n 的n变大后,遇到A:1010,B:10这样的情况,如何解读10101010?

答:而第二个问题描述的情况是不会出现的的。从构造霍夫曼树操作上可以看到,一个字符无法在另一个字符的上层(每个字符的huffman编码都是从根节点到这个字符所对应的节点的路径,而每个字符都在叶子节点上,所以一个字符对应的huffman编码不可能是另一个字符对应的huffman编码的前缀)。只要操作正确,就一定可以构造出唯一的代码表,不存在歧义。

3、还有一个有趣的问题是:虽然把40字节的内容压缩到了34字节,但需要将相应的码表一并发送给接收方(没有对应码表,无法解压)。这不反而使得压缩后的数据比压缩前的还要长?

答:事实也确实如此。本文例子中,真正的最终结果体积是大于原文的。但这不意味了算法错误。这是因为“n”过小。总长度的不够使得节省出来的那部分容量还不足以弥补码表本身的储存空间。实际应用中,如果你非要去压缩一个只有几个字节的文件,得到的压缩包也经常会大于文件本身。

通常,压缩软件会在每压缩4kb到32kb数据后,重新生成并保存一个霍夫曼树。

4、当分块过大时,统计上的整体平均,会掩盖小区域内的极度不平均,损失了压缩的空间。比如存在一个这样的文件:AAAAA……AAAAA(一万个)BBBBB……BBBBB(一万个)……ZZZZ(一万个)。

答:如果从整体上进行霍夫曼树操作,将不会产生任何压缩,但是这时候我们把它分成26块,压缩并各自保存相应的重新编码的霍夫曼树,压缩率将非常惊人,约等于12.5%。在现实的文本中,英语字母使用频率各不相同,而且差别很大。有着很高的不平均度。所以大部分压缩软件对文本文件依然有着很高的压缩率(不平均度越是高,压缩率越大)。

5、你的huffman压缩工具的优缺点?

优点:对数据不平均度高的文件,压缩效率高。对文本文件的压缩率高。只要操作正确,都能保证构成唯一的编码表。

缺点:对图片像素帧点分布平均集中的文件没有很好地压缩效果,对MP3音频文件、视频文件及文件夹不能达到压缩效果。

四、你是做测试的,那你对你这个项目都用了哪些测试用例?

1、对不同文件大小进行测试:对10kb之内的小文件,利用Beyound Compare进行对比,结果正确。对8M的文件,结果正确,但压缩时间明显加长,说明算法有待改进。

2、对不同文件格式和不同文件类型进行测试:

(1)、不同文件格式:

obj:二进制文件。

TXT:文本文件。

exe:可执行文件,应用程序。

doc word: wps文件。

xls execl:表格文件。

MP3:音乐文件。

PPT:幻灯片文件。

html:网页文件。

rar/zip:压缩文件。

git:动画文件。

com:系统可执行文件。

dll:动态链接文件。

dot:模板文件。

(2)、不同文件类型:

压缩图片:JPG的压缩率几乎是0,PNG和pdf虽然能压缩,但是压缩率非常低,说明这种算法并不适合压缩图片。(图片的像素帧点分布非常密集,这就导致数据分布平均度比较高,并不适合使用huffaman编码的方式进行压缩)。

压缩音乐:mp3格式的音乐和图片一样,用这种算法几乎没有压缩率。

压缩文件夹:程序挂掉,打开文件出错,说明这种压缩方式不能压缩文件夹。

3、总结:

文件类型:按内容来分主要有视频、音频、软件三大类。

文件格式(或文件类型):是指电脑为了存储信息而使用的对信息的特殊编码方式,是用于识别内部储存的资料。比如有的储存图片,有的储存程序,有的储存文字信息。每一类信息,都可以一种或多种文件格式保存在电脑存储中。每一种文件格式通常会有一种或多种扩展名可以用来识别,但也可能没有扩展名。扩展名可以帮助应用程序识别的文件格式。

五、你还知道那些文件压缩算法?

1、字典算法:

字典算法是最为简单的压缩算法之一。它是把文本中出现频率比较多的单词或词汇组合做成一个对应的字典列表,并用特殊代码来表示这个单词或词汇。例如:

有字典列表:

Chinese=00

People=01

China=02

源文本:I am a Chinese people,I am from China 压缩后的编码为:I am a 00 01,I am from 02。压缩编码后的长度显著缩小,这样的编码在游戏等专有名词比较多的程序中更容易出现。

2、LZ77算法

Lempel-Ziv压缩模式有许多不同的变量。基本压缩库有清晰的LZ77算法的实现(Lempel-Ziv,1977),执行的很好,源代码也非常容易理解。

LZ编码器能用来通用目标的压缩,特别对于文本文件执行的很好。

压缩:

从文件的开始到文件结束,一个字节一个字节的向后进行处理。用当前处理字节开始的串,和滑动窗口中的每个串进行匹配,寻找最长的匹配串。如果当前处理字节开始的串在窗口中有匹配串,就先输出一个标志位,表明下面是一个(之间的距离,匹配长度) 对,然后输出(之间的距离,匹配长度) 对,然后从刚才处理完的串之后的下一个字节,继续处理。如果当前处理字节开始的串在窗口中没有匹配串,就先输出一个标志位,表明下面是一个没有改动的字节,然后不做改动的输出当前处理字节,然后继续处理当前处理字节的下一个字节。

解压缩:

从文件开始到文件结束,每次先读一位标志位,通过这个标志位来判断下面是一个(之间的距离,匹配长度) 对,还是一个没有改动的字节。如果是一个(之间的距离,匹配长度)对,就读出固定位数的(之间的距离,匹配长度)对,然后根据对中的信息,将匹配串输出到当前位置。如果是一个没有改动的字节,就读出一个字节,然后输出这个字节。

我们可以看到,LZ77压缩时需要做大量的匹配工作,而解压缩时需要做的工作很少,也就是说解压缩相对于压缩将快的多。这对于需要进行一次压缩,多次解压缩的情况,是一个巨大的优点。

实际中,我们还将设定一个最小匹配长度,只有当两个串的匹配长度大于最小匹配长度时,我们才认为是一个匹配。我们举一个例子来说明这样做的原因。比如,“距离”使用15位,“长度”使用8位,那么“(之间的距离,匹配长度)对”将使用23位,也就是差1位3个字节。如果匹配长度小于3个字节的话,那么用“(之间的距离,匹配长度)对”进行替换的话,不但没有压缩,反而会增大,所以需要一个最小匹配长度。

3、固定位长算法

这种算法是把文本用需要的最少的位来进行压缩编码。

比 如八个十六进制数:1,2,3,4,5,6,7,8。转换为二进制为:00000001,00000010,00000011,00000100, 00000101,00000110,00000111,00001000。每个数只用到了低4位,而高4位没有用到(全为0),因此对低4位进行压缩编 码后得到:0001,0010,0011,0100,0101,0110,0111,1000。然后补充为字节得到:00010010, 00110100,01010110,01111000。所以原来的八个十六进制数缩短了一半,得到4个十六进制数:12,34,56,78。

这也是比较常见的压缩算法之一。

4、 RLE(Run Length Encoding)

RLE是一个针对无损压缩的非常简单的算法。它用重复字节和重复的次数来简单描述来代替重复的字节。尽管简单并且对于通常的压缩非常低效,但它有的时候却非常有用(例如,JPEG就使用它)。

举一个使用RLE算法来对一个数据流编码的例子,其中出现六次的符号‘93’已经用3个字节来代替:一个标记字节(‘0’在本例中)重复的次数(‘6’)和符号本身(‘93’)。RLE解码器遇到符号‘0’的时候,它表明后面的两个字节决定了需要输出哪个符号以及输出多少次。

这种压缩编码是一种变长的编码,RLE根据文本不同的具体情况会有不同的压缩编码变体与之相适应,以产生更大的压缩比率。

  变体1:重复次数+字符

文本字符串:A A A B B B C C C C D D D D,编码后得到:3 A 3 B 4 C 4 D。

  变体2:特殊字符+重复次数+字符

文本字符串:A A A A A B C C C C B C C C,编码后得到:B B 5 A B B 4 C B B 3 C。编码串的最开始说明特殊字符B,以后B后面跟着的数字就表示出重复的次数。

  变体3:把文本每个字节分组成块,每个字符最多重复 127 次。每个块以一个特殊字节开头。那个特殊字节的第 7 位如果被置位,那么剩下的7位数值就是后面的字符的重复次数。如果第 7 位没有被置位,那么剩下 7 位就是后面没有被压缩的字符的数量。例如:文本字符串:A A A A A B C D E F F F。编码后得到:85 A 4 B C D E 83 F(85H= 10000101B、4H= 00000100B、83H= 10000011B)。

实现RLE可以使用很多不同的方法。基本压缩库中详细实现的方式是非常有效的一个。一个特殊的标记字节用来指示重复节的开始,而不是对于重复非重复节都coding run。因此非重复节可以有任意长度而不被控制字节打断,除非指定的标记字节出现在非重复字节的稀有情况下。为了最优化效率,标记字节应该是输入流中最少出现的符号(或许就不存在)。

其他还有很多很多变体算法,这些算法在Winzip Winrar这些软件中也是经常用到的。

一个压缩文件是不是还可以用其他算法再继续压缩?

可以,但没要。压缩文件有极限值存在。高压一遍已经很接近这个值了,再压缩的话基本也就只有一丁点压缩率提升,甚至会增加体积。

六、你了解哪些常用的文件压缩工具?

haozip好压、kuaizip快压、winzip、winrar、7-zip

项目(1)——文件压缩相关推荐

  1. 【数据结构】文件压缩项目

    项目名称:文件压缩 开发环境:vs2010 运用到的数据结构: 1.heap堆 2.huffmantree哈夫曼树 3.Huffmancode哈夫曼编码 4.面向对象C++编程语言 思路: 1.利用小 ...

  2. 【小项目】用Huffman树实现文件压缩并解压

    一.前言 如果你学习数据结构,就一定会学到Huffman树,而Huffman编码实际上上就是zip压缩的核心部分,所以,如果已经学习了Huffman树,为何不尝试写一个压缩程序出来呢? 如果你没有学习 ...

  3. 项目笔记------------仿GZIP实现简易的文件压缩

    文章目录 GZIP压缩简介 基于Hhuffman树的压缩算法 原理 实现过程 整体思路 详细实现 压缩 解压缩 注意事项 基于LZ77的压缩算法 原理 实现过程 整体思路 具体实现 压缩 解压缩 注意 ...

  4. 使用System.IO.Packaging.Package进行文件压缩所产生的问题

    最近在项目中需要进行文件压缩,即将打包好的压缩文件提供给用户,用户进行下载. 获知微软提供了一个System.IO.Packaging.Package的类,从而可以进行打包,那么我就进行了使用.谁知道 ...

  5. 基于Huffman算法和LZ77算法的文件压缩的改进方向

    基于Huffman算法和LZ77算法的文件压缩(八) 到这里已经简单实现基于Huffman算法和LZ77算法的文件压缩, GitHub源码:点我 根据基于Huffman算法和LZ77算法的文件压缩(七 ...

  6. 解决 ASP.NET Core 部署到 IIS,更新项目时文件夹正在使用错误

    前言 虽然 ASP.NET Core 应用程序是跨平台的,但我们还是经常将它部署到 Windows 的 IIS 下. 当 ASP.NET Core 站点运行时,它会锁定正在使用的程序集,如果这时向站点 ...

  7. 基于哈夫曼编码完成的文件压缩及解压

    这几天在较为认真的研究基于哈夫曼编码的文件压缩及解压,费了点时间,在这分享一下: 这里用链式结构,非顺序表结构: 文件压缩: 1.获取文件信息(这里采用TXT格式文本): 2.压缩文件: 3.写配置文 ...

  8. javaweb通过接口来实现多个文件压缩和下载(包括单文件下载,多文件批量下载)

      程序员在做web等项目的时候,往往都需要添加文件上传.下载.删除的功能,有时是单文件,有时多文件批量 操作,而这些功能的代码程序员可以自己收藏起来当成工具使用,这样,程序员在进行程序设计的时候就会 ...

  9. php excel模板导出、openoffice excel转pdf、多文件压缩下载

    最近两周都在弄关于excel模板导出.excel转pdf.多文件压缩下载.弄得头都大了,接下来说说实现的方法吧. 我用的是laravel5.1的框架,读取模板生成excel,并且插入图片,直接上代码 ...

  10. python zipapp_python zip文件 压缩

    Python读写zip压缩文件 Python自带模块zipfile可以完成zip压缩文件的读写,而且使用非常方便,下面我们就来演示一下Python读写zip文件. Python读zip文件 下面的代码 ...

最新文章

  1. 算法开发人员的安身之本:如何将机器学习与各行各业进行深度结合
  2. ubuntu下 mysql数据 自执行备份
  3. ------ 比较二位数组大小-----
  4. 怎样查看rpm安装包的安装路径
  5. [Ubuntu] Ubuntu系统环境变量详解
  6. 微信小程序 地图组件使用
  7. 题解 LGOJ P4168 【[Violet]蒲公英】
  8. 《.NET大局观》--嬗变的痛苦
  9. 概率论与数理统计 期末突击复习
  10. IDEA 中 project窗口,不显示项目工程目录,解决方法
  11. JS获取当前时间是否为节假日,周末
  12. EXCEL学生成绩里计算年级名次、班级名次
  13. Java中对象转换为字符串的几种方式
  14. 广州软博前端实习生面经
  15. 医疗ChatGPT、金融GPT都来啦!“潘多拉的魔盒”已经打开?
  16. L1-057 PTA使我精神焕发 - java
  17. jmeter正则表达式提取器的用法和正则
  18. 【2018/10/27测试T1】洛阳怀
  19. linux的ping命令-l参数,linux下 ping命令参数
  20. Matlab求一元函数极值

热门文章

  1. BigGAN高保真自然图像合成的大规模GAN训练
  2. java计算机毕业设计大数据在线考试系统在线阅卷系统及大数据统计分析MyBatis+系统+LW文档+源码+调试部署
  3. C++一个简单的弹窗程序
  4. 《网络科学导论》——博弈模型笔记
  5. Verilog一个非常简洁的8选1多路选择器
  6. eviews建立时间序列模型_模型建立——时间序列 eviews协整检验(EG两步法(Engle-Granger))...
  7. hdu2553解题报告
  8. 逐星mrp生产管理系统 msn软件下载
  9. matlab瑞利衰落信道仿真
  10. 优盘安装红帽linux系统,RedHat Linux系统U盘安装图文教程