Android?數(shù)據(jù)壓縮淺析
1. 前言
在開發(fā)中我們難免會碰到傳輸?shù)臄?shù)據(jù)太大,或者傳輸?shù)馁Y源過大,所以就出現(xiàn)了數(shù)據(jù)壓縮這項技術(shù),現(xiàn)在存在很多種數(shù)據(jù)壓縮的算法,每種算法都有自己的特點和使用場景,這次就想簡單來聊聊關(guān)于數(shù)據(jù)壓縮這件事。
為什么會想到這個問題,因為碰到了一些場景,我不知道是大家對數(shù)據(jù)壓縮這個概念太模糊不敢去使用,還是因為深思熟慮覺得影響性能太大不想用。我這有個需求,給鏈接拼接參數(shù),然后跳轉(zhuǎn)這個鏈接,另外一邊從中拿到拼接的參數(shù),其實就是get請求,但是,現(xiàn)在的情況是拼接后的鏈接又臭又長,就是url?a=xxx&b=xxx&c=xxx......這種,然后就瘋狂往后面拼參數(shù)。把整個對象拆了往后面拼。那為何不把對象轉(zhuǎn)成json然后壓縮呢?
是覺得字符串不能壓縮?還是設(shè)計時沒有意識到還有壓縮這事?還是覺得你幾十年的開發(fā)直覺告訴你使用壓縮會出大問題。
2. 關(guān)于壓縮這件事
首先什么是數(shù)據(jù)壓縮?舉個簡單的例子,我把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", "壓縮后結(jié)果" + result); return result; } }
在外部調(diào)用
String str = "ABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDEABCDE"; String result = Test.compress(str);
可以看到結(jié)果
壓縮后結(jié)果eNpzdHJ2cXUkhQAATY4NFw
看得出壓縮前和壓縮后的一個明顯的效果。
有人看到這個可能就想到,哦,原來用Base64壓縮,這是一個誤區(qū),有一定開發(fā)經(jīng)驗或者一定基礎(chǔ)的朋友都知道,但是可能一些萌新不太熟,我前面也寫過了,Base64不是壓縮,是一種編碼,如果你純用Base64的話,它只會變得更長。
那為什么還要在這里用Base64呢?Base64是為了將字節(jié)數(shù)組轉(zhuǎn)成字符串,數(shù)據(jù)壓縮和解壓的對象是字節(jié)數(shù)組,所以壓縮可以對字符串壓縮,也可以對文件壓縮,因為它是針對byte[]
有的人就會說,懂了,那簡單,那我圖片和視頻的壓縮也用Deflater。這東西還真不一樣,壓縮又分為有損壓縮和無損壓縮,我們上面使用Deflater進行的壓縮是無損壓縮,是可逆的,而圖片和視頻的壓縮往往會用有損壓縮比較多,特別是視頻,壓縮率很高,因為有損壓縮能把數(shù)據(jù)壓得更小,相對得它是不可逆的。所以對數(shù)據(jù)和資源要使用哪種壓縮方式要看具體的場景。比如這里的對字符串壓縮,要是使用有損的方式,那解壓出來的字符串不就和原字符串內(nèi)容不同了嗎。
相信看到這里,你已經(jīng)對數(shù)據(jù)的壓縮這個概念有個大概的了解。
3. Deflater算法
前面有說到數(shù)據(jù)壓縮的算法有很多種,甚至你也可以自己設(shè)計出一套算法,然后寫專利。而Deflater算法是一種常用的數(shù)據(jù)無損壓縮算法。
可以很容易的找到Deflate壓縮算法=LZ77+哈夫曼編碼,意思是這套算法內(nèi)部的實現(xiàn)原理就是使用LZ77和哈夫曼編碼。
我這邊暫時先不講這些算法的實現(xiàn)過程和原理,因為內(nèi)容也是比較多,如果以后有時間單獨拿出來寫,并且手寫一遍用代碼去實現(xiàn)這些算法(一般都是用C寫) ,這里就只簡單介紹一下,有個概念就行。
LZ77
LZ77編碼是一種基于字典的、“滑動窗”的無損壓縮算法。
簡單來說就是滑動的過程中,把前面的子串放到字典中,滑動到后面發(fā)現(xiàn)相同的子串時只需要替換成子串的位置和長度的信息進去就行。
例如ABCDEFABCDZZZ → ABCDEF(6,4)ZZZ
意思是往前第6個,長度為4。
當然這只是簡單的一個體現(xiàn)思路的例子,實際中肯定沒有這么簡單,比如子串怎么找啊,滑動怎么滑等等之類的。
哈夫曼編碼
哈夫曼編碼,又涉及到哈夫曼樹,貪心算法。該方法完全依據(jù)字符出現(xiàn)概率來構(gòu)造異字頭的平均長度最短的碼字。
因為這個要根據(jù)字符出現(xiàn)的頻率構(gòu)建哈夫曼樹,不好簡單易懂的演示出來,這里就拿一個別人寫的Demo來直接演示效果。
原字符串:BCAADDDCCACACAC
轉(zhuǎn)成二進制后:
10000100100001101000001010000010100010001000100010001000100001101000011010000010100001101000001010000110100000101000011
編碼后:1000111110110110100110110110
能看出壓縮的效果很明顯。
小結(jié)
Deflater算法是一種常用的數(shù)據(jù)壓縮算法,其內(nèi)部是使用LZ77和哈夫曼編碼。壓縮算法一般都具備平臺無關(guān)性,它是一種計算,一種思想,java使用的是Deflater這個類,php也有對應(yīng)的庫,go也有對應(yīng)的庫。甚至當你知道了它的原理之后,你也能自己把實現(xiàn)過程給寫出來,當然這很麻煩,畢竟涉及算法還是有一定難度。所以一般在開發(fā)中你得知道有這么一個東西,它是干嘛的,怎么使用。當然最好還是能知道它的原理,知道它怎么實現(xiàn)的,這并不是毫無作用,當你去學(xué)之后,你一定能收獲到一些東西。
可以再擴展一下,像圖片的質(zhì)量壓縮,就是一種有損壓縮的方式,像視頻的H264編碼,H265編碼等,也是一個有損的過程。要心里有個底,對這個數(shù)據(jù)進行操作,是否需要可逆,是否是針對它的大小,可逆就用無損壓縮的算法,為了極致的壓縮大小又無所謂不可逆,那就用有損壓縮的算法。對數(shù)據(jù)的傳輸是否要安全,全都無所謂就明文傳輸最快,對其大小有要求就壓縮,要求安全就加密。開發(fā)就這么簡單!
GZIP
GZIP也是一種壓縮技術(shù),相信很多人都聽說過。我們的http請求頭中可以配置content-encoding為gzip,那么服務(wù)端返回的數(shù)據(jù)就是經(jīng)過gzip壓縮過之后的數(shù)據(jù)。那有什么用呢?你文件大,字節(jié)數(shù)多,傳輸?shù)乃俣染吐?,我?jīng)過gizp壓縮之后,壓縮率高,傳輸?shù)淖止?jié)數(shù)少很多,那傳輸?shù)乃俣染涂臁?/p>
有的人也會說,那你壓縮可解壓也是耗時間的啊。說得好,這種我建議你不要信什么原理,直接去實踐,去試試使用GZIP壓縮和不使用韓國,誰得速度更快。當然數(shù)據(jù)量大的情況下去測。你會發(fā)現(xiàn)哪怕我經(jīng)過壓縮和解壓,也比你直接傳輸?shù)乃俣雀臁?/p>
GZIP中的實現(xiàn)也包含了Deflater算法。所以能看出來,壓縮算法很多,基本都萬變不離其宗,基本都是靠LZ77和哈夫曼,為什么呢?因為別人好用啊,你寫不出比它更厲害的,那不用它的用什么。
以上就是Android 數(shù)據(jù)壓縮淺析的詳細內(nèi)容,更多關(guān)于Android 數(shù)據(jù)壓縮的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
淺談Android輕量級的數(shù)據(jù)緩存框架RxCache
本篇文章主要介紹了淺談Android輕量級的數(shù)據(jù)緩存框架RxCache,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08基于Android CALL && SendMes Test的相關(guān)介紹
本篇文章小編為大家介紹,Android CALL && SendMes Test 需要的朋友參考下2013-04-04