以前對壓縮演算法一無所知,只是知道哈弗曼編碼能做這種事情,但是感覺這樣的方法奇慢無比。昨天下午看了下號稱世界上最快的壓縮演算法quicklz,對壓縮的基本思路有了一定的了解。一般的壓縮程式的要求讀入檔案之後以便壓縮一邊輸出,而不是去先分析整個檔案中的情況之後才做決定採取哪種演算法。
quicklz也不例外也是爭取利用檔案中重複出現的位元組來進行壓縮,管理結構如下:
在壓縮的過程中不斷地讀入3個位元組,然後根據這3個位元組得到乙個hash值,根據這個hash值就可以找到offset,這個offset就是上次這個hash值出現的位置,而通過cache可以判斷出這次出現的和最近一次出現相同hash值的時候的3個位元組是不是相同(可能hash相同而實際的值不同)。
如果相同的長度在3到18之間,那麼這些情況可以用4個位來表示。而大於18小於255的情況則需要8位來表示,剛才用於表示長度的低4為則全部變為0,以區別兩種情況。在level=1的時候就只有這兩種情況了。在壓縮的過程中用4個位元組來記錄壓縮操作,如果有壓縮則為1,否則為0。下面是level=1時候的情況:
level=1的時候有個很明顯的問題是只記錄了乙個hash相同時候的cache,這樣的話只能等到與上次的值相同才能壓縮,而與以前的值相同也不行。在level=2和level=3的時候彌補了這個缺陷,但是代價就是壓縮的時間變長。在level=2的時候儲存了4個offset(相同hash的位置),然後在這四個中取到重複位元組長度最長的乙個作為壓縮選項(這個值儲存在最低的2位中),而重複的長度資訊儲存在接下來的3個位中(如果夠的話,不然初始化這3個位為0,在hash值後面的乙個位元組中儲存),其他的地方就和level=1的時候相同了。壓縮後檔案的格式如下:
在上面的情況中我們發現如果是3個位元組相同的話只能把它壓縮成2個位元組。而在level=3的時候彌補了這個缺陷,在level=3的時候與前兩個的不同之處是最低的兩位統一作為標誌,記錄進行了什麼操作,具體的**如下:
複製**
複製**
if(matchlen == 3 && offset <= 63)
else if (matchlen == 3 && offset <= 16383)
else if (matchlen <= 18 && offset <= 1023)
else if(matchlen <= 33)
else
複製**
複製**
雖然最後的兩種情況的最低兩位都是11,但是從下面的格式圖中一眼就能看出區別(對應上面的**看):
這裡知道了檔案被壓縮後儲存的儲存格式,下面考慮一下怎麼解壓。在level=3的時候解壓方法還是很好理解的。但是在level=1和level=2的時候怎麼解壓呢?畢竟壓縮檔案中只是儲存了hash值,而沒有指出重複的位元組串,甚至連offset都沒有給出。這裡其實很好理解,因為第一次遇到乙個hash的時候當然是不會去壓縮它的,那麼在解壓程式中我們就得到了offset的值,並且隨著解壓的進行,hash和offset的值與壓縮時候的變化是相同的,所有不必儲存這些值也能保證正確的解壓。
Quicklz壓縮演算法
以前對壓縮演算法一無所知,只是知道哈弗曼編碼能做這種事情,但是感覺這樣的方法奇慢無比。昨天下午看了下號稱世界上最快的壓縮演算法quicklz,對壓縮的基本思路有了一定的了解。一般的壓縮程式的要求讀入檔案之後以便壓縮一邊輸出,而不是去先分析整個檔案中的情況之後才做決定採取哪種演算法。quicklz也不...
quicklz 介面函式
翻譯自quicklz c手冊 壓縮函式 size t qlz compress const void source,char destination,size t size,qlz state compress state compress source,源字元位址 destination,壓縮後的...
使用quicklz縮小程式體積
目錄將二進位制檔案生成c陣列程式 有乙個需求是這樣的,寫的乙個程式內建了乙個很大的檔案 實際就是抓取epsg.io的內容裡面的epsg.io.json 這個檔案篩選縮減後還有12mb,如果直接內建到程式中,編譯後的程式就很大了。因為這個程式是乙個動態庫,而使用upx壓縮過的動態庫有時候會有一些異常問...