Android 数据压缩浅析
作者:流浪汉kylin
1. 前言
在开发中我们难免会碰到传输的数据太大,或者传输的资源过大,所以就出现了数据压缩这项技术,现在存在很多种数据压缩的算法,每种算法都有自己的特点和使用场景,这次就想简单来聊聊关于数据压缩这件事。
为什么会想到这个问题,因为碰到了一些场景,我不知道是大家对数据压缩这个概念太模糊不敢去使用,还是因为深思熟虑觉得影响性能太大不想用。我这有个需求,给链接拼接参数,然后跳转这个链接,另外一边从中拿到拼接的参数,其实就是get请求,但是,现在的情况是拼接后的链接又臭又长,就是url?a=xxx&b=xxx&c=xxx......这种,然后就疯狂往后面拼参数。把整个对象拆了往后面拼。那为何不把对象转成json然后压缩呢?
是觉得字符串不能压缩?还是设计时没有意识到还有压缩这事?还是觉得你几十年的开发直觉告诉你使用压缩会出大问题。
2. 关于压缩这件事
首先什么是数据压缩?举个简单的例子,我把AAABBBCCC这个字符串变成3A3B3C,就是一种压缩的思想。
写个Demo演示一下java使用Deflater对字符串进行压缩
public class Test { public static String compress(String str) { Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION); deflater.setInput(str.getBytes()); deflater.finish(); final byte[] bytes = new byte[256]; ByteArrayOutputStream bos = new ByteArrayOutputStream(256); while (!deflater.finished()) { int length = deflater.deflate(bytes); bos.write(bytes, 0, length); } deflater.end(); String result = Base64.encodeToString(bos.toByteArray(), Base64.NO_PADDING); Log.v("mmp", "压缩后结果" + result); return result; } }
在外部调用
String str = "ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE"; String result = Test.compress(str);
可以看到结果
压缩后结果eNpzdHJ2cXUkhQAATY4NFw
看得出压缩前和压缩后的一个明显的效果。
有人看到这个可能就想到,哦,原来用Base64压缩,这是一个误区,有一定开发经验或者一定基础的朋友都知道,但是可能一些萌新不太熟,我前面也写过了,Base64不是压缩,是一种编码,如果你纯用Base64的话,它只会变得更长。
那为什么还要在这里用Base64呢?Base64是为了将字节数组转成字符串,数据压缩和解压的对象是字节数组,所以压缩可以对字符串压缩,也可以对文件压缩,因为它是针对byte[]
有的人就会说,懂了,那简单,那我图片和视频的压缩也用Deflater。这东西还真不一样,压缩又分为有损压缩和无损压缩,我们上面使用Deflater进行的压缩是无损压缩,是可逆的,而图片和视频的压缩往往会用有损压缩比较多,特别是视频,压缩率很高,因为有损压缩能把数据压得更小,相对得它是不可逆的。所以对数据和资源要使用哪种压缩方式要看具体的场景。比如这里的对字符串压缩,要是使用有损的方式,那解压出来的字符串不就和原字符串内容不同了吗。
相信看到这里,你已经对数据的压缩这个概念有个大概的了解。
3. Deflater算法
前面有说到数据压缩的算法有很多种,甚至你也可以自己设计出一套算法,然后写专利。而Deflater算法是一种常用的数据无损压缩算法。
可以很容易的找到Deflate压缩算法=LZ77+哈夫曼编码,意思是这套算法内部的实现原理就是使用LZ77和哈夫曼编码。
我这边暂时先不讲这些算法的实现过程和原理,因为内容也是比较多,如果以后有时间单独拿出来写,并且手写一遍用代码去实现这些算法(一般都是用C写) ,这里就只简单介绍一下,有个概念就行。
LZ77
LZ77编码是一种基于字典的、“滑动窗”的无损压缩算法。
简单来说就是滑动的过程中,把前面的子串放到字典中,滑动到后面发现相同的子串时只需要替换成子串的位置和长度的信息进去就行。
例如ABCDEFABCDZZZ → ABCDEF(6,4)ZZZ
意思是往前第6个,长度为4。
当然这只是简单的一个体现思路的例子,实际中肯定没有这么简单,比如子串怎么找啊,滑动怎么滑等等之类的。
哈夫曼编码
哈夫曼编码,又涉及到哈夫曼树,贪心算法。该方法完全依据字符出现概率来构造异字头的平均长度最短的码字。
因为这个要根据字符出现的频率构建哈夫曼树,不好简单易懂的演示出来,这里就拿一个别人写的Demo来直接演示效果。
原字符串:BCAADDDCCACACAC
转成二进制后:
10000100100001101000001010000010100010001000100010001000100001101000011010000010100001101000001010000110100000101000011
编码后:1000111110110110100110110110
能看出压缩的效果很明显。
小结
Deflater算法是一种常用的数据压缩算法,其内部是使用LZ77和哈夫曼编码。压缩算法一般都具备平台无关性,它是一种计算,一种思想,java使用的是Deflater这个类,php也有对应的库,go也有对应的库。甚至当你知道了它的原理之后,你也能自己把实现过程给写出来,当然这很麻烦,毕竟涉及算法还是有一定难度。所以一般在开发中你得知道有这么一个东西,它是干嘛的,怎么使用。当然最好还是能知道它的原理,知道它怎么实现的,这并不是毫无作用,当你去学之后,你一定能收获到一些东西。
可以再扩展一下,像图片的质量压缩,就是一种有损压缩的方式,像视频的H264编码,H265编码等,也是一个有损的过程。要心里有个底,对这个数据进行操作,是否需要可逆,是否是针对它的大小,可逆就用无损压缩的算法,为了极致的压缩大小又无所谓不可逆,那就用有损压缩的算法。对数据的传输是否要安全,全都无所谓就明文传输最快,对其大小有要求就压缩,要求安全就加密。开发就这么简单!
GZIP
GZIP也是一种压缩技术,相信很多人都听说过。我们的http请求头中可以配置content-encoding为gzip,那么服务端返回的数据就是经过gzip压缩过之后的数据。那有什么用呢?你文件大,字节数多,传输的速度就慢,我经过gizp压缩之后,压缩率高,传输的字节数少很多,那传输的速度就快。
有的人也会说,那你压缩可解压也是耗时间的啊。说得好,这种我建议你不要信什么原理,直接去实践,去试试使用GZIP压缩和不使用韩国,谁得速度更快。当然数据量大的情况下去测。你会发现哪怕我经过压缩和解压,也比你直接传输的速度更快。
GZIP中的实现也包含了Deflater算法。所以能看出来,压缩算法很多,基本都万变不离其宗,基本都是靠LZ77和哈夫曼,为什么呢?因为别人好用啊,你写不出比它更厉害的,那不用它的用什么。
以上就是Android 数据压缩浅析的详细内容,更多关于Android 数据压缩的资料请关注脚本之家其它相关文章!