文件压缩比的压缩比怎么用Java程序计算

本文将会对常用的几个压缩算法嘚性能作一下比较结果表明,某些算法在极端苛刻的CPU限制下仍能正常工作

JDK deflate ——这是JDK中的又一个算法(zip文件压缩比用的就是这一算法)。它与gzip的不同之处在于你可以指定算法的压缩级别,这样你可以在压缩时间和输出文件压缩比大小上进行平衡可选的级别有0(不压缩),以及1(快速压缩)到9(慢速压缩)它的实现是java.util.zip.DeflaterOutputStream / InflaterInputStream。
的Java实现——这是本文介绍的算法中压缩速度最快的一个与最快速的deflate相比,它的压缩的結果要略微差一点
——这是Google开发的一个非常流行的压缩算法,它旨在提供速度与压缩比都相对较优的压缩算法

要找出哪些既适合进行數据压缩测试又存在于大多数Java开发人员的电脑中(我可不希望你为了运行这个测试还得个几百兆的文件压缩比)的文件压缩比也着实费了峩不少工夫。最后我想到大多数人应该都会在本地安装有JDK的文档。因此我决定将javadoc的目录整个合并成一个文件压缩比——拼接所有文件压縮比这个通过tar命令可以很容易完成,但并非所有人都是Linux用户因此我写了个程序来生成这个文件压缩比:

 
 
 

在我的机器上整个文件压缩比嘚大小是354,509,602字节(338MB)。

一开始我想把整个文件压缩比读进内存里然后再进行压缩。不过结果表明这么做的话即便是4G的机器上也很容易把堆內存空间耗尽

于是我决定使用操作系统的文件压缩比缓存。这里我们用的测试框架是JMH这个文件压缩比在预热阶段会被操作系统加载到緩存中(在预热阶段会先压缩两次)。我会将内容压缩到ByteArrayOutputStream流中(我知道这并不是最快的方法但是对于各个测试而言它的性能是比较稳定嘚,并且不需要花费时间将压缩后的数据写入到磁盘里)因此还需要一些内存空间来存储这个输出结果。

下面是测试类的基类所有的測试不同的地方都只在于压缩的输出流的实现不同,因此可以复用这个测试基类只需从StreamFactory实现中生成一个流就好了:

 
 
 

这些测试用例都非常楿似(在文末有它们的源代码),这里只列出了其中的一个例子——JDK deflate的测试类;

 

输出文件压缩比的大小首先我们来看下输出文件压缩比的夶小:



可以看出文件压缩比的大小相差悬殊(从60Mb到131Mb)我们再来看下不同的压缩方法需要的时间是多少。



我们再将压缩时间和文件压缩比夶小合并到一个表中来统计下算法的吞吐量看看能得出什么结论。



可以看到其中大多数实现的效率是非常低的:在Xeon E5-2650处理器上,高级别嘚deflate大约是23Mb/秒即使是GZIP也就只有33Mb/秒,这大概很难令人满意同时,最快的defalte算法大概能到75Mb/秒,Snappy是150Mb/秒而LZ4(快速,JNI实现)能达到难以置信的320Mb/秒!

从表中鈳以清晰地看出目前有两种实现比较处于劣势:Snappy要慢于LZ4(快速压缩)并且压缩后的文件压缩比要更大。相反LZ4(高压缩比)要慢于级别1到4的deflate,而输出文件压缩比的大小即便和级别1的deflate相比也要大上不少

因此如果需要进行“实时压缩”的话我肯定会在LZ4(快速)的JNI实现或者是级别1的deflate中進行选择。当然如果你的公司不允许使用第三方库的话你也只能使用deflate了你还要综合考虑有多少空闲的CPU资源以及压缩后的数据要存储到哪裏。比方说如果你要将压缩后的数据存储到HDD的话,那么上述100Mb/秒的性能对你而言是毫无帮助的(假设你的文件压缩比足够大的话)——HDD的速度会成为瓶颈同样的文件压缩比如果输出到SSD硬盘的话——即便是LZ4在它面前也显得太慢了。如果你是要先压缩数据再发送到网络上的话最好选择LZ4,因为deflate75Mb/秒的压缩性能跟网络125Mb/秒的吞吐量相比真是小巫见大巫了(当然我知道网络流量还有包头,不过即使算上了它这个差距吔是相当可观的)

如果你认为数据压缩非常慢的话,可以考虑下LZ4(快速)实现它进行文本压缩能达到大约320Mb/秒的速度——这样的压缩速喥对大多数应用而言应该都感知不到。
如果你受限于无法使用第三方库或者只希望有一个稍微好一点的压缩方案的话可以考虑下使用JDK deflate(lvl=1)进荇编解码——同样的文件压缩比它的压缩速度能达到75Mb/秒。

本博客来自我的新书Java性能优化(暫定名)第5章的Java代码优化技巧节选20,也欢迎阅读我的新书

JMH测试结果如下可以看到即使20K报文内容,压缩的速度还是非常快的在不到1毫秒。100K报文则需要较长时间,默认压缩(-1)需要4毫秒左右

这个测试选用的是一篇文章作为压缩内容,你需要根据你的业务情况用真实嘚报文来做压缩测试,事实上如果是XML或者JSON报文,有着非常大的压缩比

本节选择了zip压缩方式,还有其他可选方式比如gzip,bzip2,7z等等可以使鼡开源库Apache Commons Compress进行压缩,在笔者测试后发现zip还是一种压缩比和性能都比较好的方式。7z具有最大的压缩比但压缩时长超过百毫秒,在实时的業务系统中是不可接受的

对于解压来说,无论采用何种压缩方式何种压缩级别,解压需要的时间都是非常少的限于篇幅就不再说明,读者有兴趣可以使用本书附带例子ZipUtil.decompress 测试对比一下

    之前用了一个哈弗曼算法给大家實现了文件压缩比的压缩处理其实上,文件压缩比压缩的原理很简单无非就是把重复出现的元素,用一个特定的方式转化为跟少量的信息来存储今天我所给大家分享的就是一个更为引用广泛的压缩算法lzw压缩算法。

     LZW压缩算法是一种新颖的压缩方法由Lemple-Ziv-Welch 三人共同创造,用怹们的名字命名它采用了一种先进的串表压缩,将每个第一次出现的串放在一个串表中用一个数字来表示串,压缩文件压缩比只存贮數字则不存贮串,从而使图象文件压缩比的压缩效率得到较大的提高奇妙的是,不管是在压缩还是在解压缩的过程中都能正确的建立這个串表压缩或解压缩完成后,这个串表又被丢弃

Ababcabab这个字符串,开起来9个字符组成的但是会发现一点就是ab这个字符组合比较的多。洳果我们用一个数字也就是7来表示ab的话,则字符串就变为了77c77这样一来字符串的字符个数就变为了5个,如果大家仔细些会发现如果我們用一个数字8来表示abab,则原来的字符串就变为了8c8只有3个字符了是不是很神奇哈。

从这个例子我们就可以看出LZW算法的适用范围是原始数据串最好是有大量的子串多次重复出现重复的越多,压缩效果越好反之则越差,可能真的不减反增了


压缩后效果就非常的显著:

文件壓缩比大小变为原来的1/30

比如我们大家所熟知的ASCII码,这个码表是与我们常见的字符是一一对应的比如我们说‘a,我们也可以写成97,这两者僦是等价的其实上这就是一个码表。所以人们就想到我们可不可以用以一个码表示一个或者多个的字符,比如8表示ab这两字符我们就能将abcab这种的字符串缩小为8c8了。 但是我们知道字节只有0~255如果我们要扩展的话就必须增加自己的定义。既我假设我用增加了256~65534这么一段表示噺的码表。

①打开一个待压缩文件压缩比与存放压缩后的文件压缩比

②读入一个字节作为后缀判断这个词字典中是否存在,存在则直接輸出不存在则加入字典中。

③如果超过了最大的长度则将当前码表写出到文件压缩比中,清空再次读入

最后,将没有写完的信息和码表都输出,压缩就完成了

后最suffix:反之为后一个字符,比如 ab,后缀为b8f后缀为f

有了前缀后缀,我们就能清楚的表示出来一个词了

把輸出来的和最后一个后缀连在一起则是:

6个字符,那么就达到了压缩的目的

解压缩就很简单了,将输出字符串按照码表对应转化回来就實现了

当然我们不能一直无穷之境的增加码表的长度,再说内存也容不下这么长的码表正如我之前所说的,我用了0~65534保存字节所对应的編码0~255是系统字节的长度,256~65534是我自己定义的如果超过了65534的话,我们这必须再次编码即将原来所对应的编码输出,将256~65534这一段清空再次編码就可以了。

为了记录我们是在哪里清空的所有又在文件压缩比中写一个字符,表示 “清除”我的程序中用的是65535表示。

①打开一个待压缩文件压缩比与存放压缩后的文件压缩比

②读入一个字节作为后缀判断这个词字典中是否存在,存在则直接输出不存在则加入字典中。

③如果超过了最大的长度则将当前码表写出到文件压缩比中,清空再次读入

④最后,将没有写完的信息和码表都输出,压缩僦完成了

①读入码表之前的压缩信息

③翻译编码写出源文件压缩比

//解压缩、写出该部分的源文件压缩比
 
比较,lzw和哈弗曼做比较lzw的代码哽为简便,实现更为简单效率也比哈弗曼高。但是LZW得算法比较难以理解

声明:ITeye文章版权属于作者,受法律保护没有作者书面许可不嘚转载。

这个应该就是GIF所使用的压缩编码方式吧

这个应该就是GIF所使用的压缩编码方式吧?

是的忘记说了,lzw的主要应用就是GIF

标题党 充其量是个算法的例子

讲得挺好啊.压缩数据还是第一次看到有这个好例子,挺不错.我现在要做的IPHONE网游后台也涉及到了数据压缩,但是必需得以抛包的形式传递,目前还没有思路!

我要回帖

更多关于 文件压缩比 的文章

 

随机推荐