基于LZ77算法的文件解压缩项目缺陷分析
基于Huffman算法和LZ77算法的文件壓縮(七)
基于Huffman算法和LZ77算法的文件壓縮(六)已經講解完文件壓縮的過程,本文講解文件解壓縮的過程和大文件處理方式
一、解壓縮的流程
LZ77的解壓縮非常簡單:
二、合并標記信息文件和壓縮數據文件
- 開始解壓縮前我們需要合并壓縮數據文件和標記信息文件,那么合并到一起怎么區分壓縮數據和標記信息呢?
- 我們還要在合并后的壓縮文件當中寫入標記信息的總字節數和原數據文件的大小。
- 注意合并完成后文件大小和標記信息大小的 獲取方式:
- 合并文件
- 注意讀取標記信息文件指針的起始位置
-
合并完后,解壓縮的流程:
三、開始解壓縮 -
同樣還是先在標記文件當中讀取一個字節chFlag(其8個比特位的01就代表是原字符還是長度距離對),& 0x80來判斷高位01情況
-
注意如果標記信息是1,就代表是長度距離對,把長度讀取出來需要 + 3。
-
如果是長度距離信息,需要再來一個文件指針,從解壓縮文件末尾往前偏移距離個位置(即定位到匹配字符的開始),然后往后寫長度個字符到解壓縮文件
-
注意注意在,操作系統為了提高讀取寫入的效率,是提供緩沖區的機制,如果你向文件當中寫入數據,其實是寫到緩沖區當中,緩沖區滿就才會往文件當中寫,而前面我們說過,解壓縮的文件是有兩個指針打開的(一個是寫壓縮數據,一個是定位匹配字符的開始位置),現在如果寫壓縮數據的文件指針把數據寫入到緩沖區并沒有寫入到文件,此時定位匹配字符開始位置的指針需要讀取長度個字符寫入到解壓縮文件,這樣就會報錯,因為壓縮文件當中的數據還在緩沖區,代表壓縮文件當中沒有數據,你去讀取,就只能讀取一個255,就達不到解壓縮的目的。怎么解決呢??? 刷新緩沖區
解壓縮完整代碼:
//解壓縮 void LZ77::UNCompressFile(const std::string& strFilePath) {//打開壓縮文件和標記文件FILE* fInD = fopen(strFilePath.c_str(), "rb");if (nullptr == fInD) {std::cout << "壓縮文件打開失敗" << std::endl;return;}//操作標記數據的文件指針FILE* fInF = fopen(strFilePath.c_str(), "rb");if (nullptr == fInF) {std::cout << "壓縮文件打開失敗" << std::endl;return;}//獲取源文件大小ULL fileSize = 0;fseek(fInF, 0 - sizeof(fileSize), SEEK_END);fread(&fileSize, sizeof(fileSize), 1, fInF);//獲取標記信息的大小size_t flagSize = 0;fseek(fInF, 0 - sizeof(fileSize) - sizeof(flagSize), SEEK_END);fread(&flagSize, sizeof(flagSize), 1, fInF);//將讀取標記信息的文件指針移動到保存標記數據的起始位置fseek(fInF, 0 - sizeof(flagSize) - sizeof(fileSize) - flagSize, SEEK_END);//開始解壓縮//寫解壓縮數據//FILE* ffOut = fopen("5.txt","rb");//std::string filestr ;//std::cout<<filestr<<std::endl;//fread(&filestr,sizeof(filestr),1,ffOut);//std::string str = "4.";//str += filestr;//fclose(ffOut);FILE* fOut = fopen("4.txt", "wb");assert(fOut);FILE* fR = fopen("4.txt", "rb");assert(fR);UCH bitCount = 0;UCH chFlag = 0;ULL encodeCount = 0;//標記已經解壓縮的數據大小,方便判斷解壓縮的結束while (encodeCount < fileSize) {//讀取標記if (0 == bitCount) {//讀取一個字節chFlag=fgetc(fInF);bitCount = 8;}if (chFlag & 0x80)//當前字節的高位為1 {//距離長度對USH matchLen = fgetc(fInD) + 3;//長度USH matchDist = 0;//距離fread(&matchDist, sizeof(matchDist), 1, fInD);//清空緩沖區,非常重要fflush(fOut);//更新已經解碼的字節數大小encodeCount += matchLen;//fR:讀取前文匹配串中的內容UCH ch;fseek(fR, 0 - matchDist, SEEK_END);while (matchLen) {ch = fgetc(fR);fputc(ch, fOut);--matchLen;//在還原長度距離對時,一定要清空緩沖區,否則可能會還原出錯fflush(fOut);}}else {//原字符UCH ch = fgetc(fInD);fputc(ch, fOut);encodeCount += 1;}chFlag <<= 1;bitCount--;}fclose(fInD);fclose(fInF);fclose(fOut);fclose(fR); }到這里,簡單的文件解壓縮已經OK,接下來就針對大文件的壓縮和解壓縮進行補充
四、大文件處理
2.填充窗口
- 注意源文件就是小文件的情況,那么在壓縮一部分后,源文件已經沒有數據,文件指針已經走到文件的末尾,如果再去向右窗填充數據,就會報錯,需要判斷
3.注意查找范圍和壓縮范圍重疊的情況
- 下圖這種情況當指針走到BD的時候,匹配字符串的長度距離是多少?(5,3)
- 為什么指針在E4的時候不進行匹配呢?按理說是可以進行一次匹配的。答案就是哈希表的結構引起的,我們在初始化的時候把哈希表當中的每個位置都設為0,代表匹配結束即到達匹配鏈的末尾,在這里,E4 BD A0經過哈希函數計算出哈希地址后,在相應哈希地址的位置放E4這個字符在緩沖區當中的下標,而這個下標剛好又為0,在第二個E4到來之后,拿到的匹配頭為0,所以是不進行匹配的
- 這種情況下,還原長度距離對還需要刷新緩沖區,到這里解壓縮就需要2次刷新緩沖區
到這里基于LZ77算法的文件壓縮已經完成
五、總結
我們的項目是基于GZIP的思想進行壓縮的。
1.總結GZIP壓縮的思想
2.項目的缺陷
- 當前已完成基于Huffman和LZ77算法的文件壓縮與解壓縮。
- 改進的方向就是把Huffman和LZ77算法的文件壓縮與解壓縮結合起來,模擬GZIP
- 但是不能直接把LZ77的壓縮結果用Huffman進行壓縮,原因是壓縮率不理想
3.項目的改進方向
- 不要直接對LZ77的壓縮結果采用Huffman樹的方法進行壓縮-----Huffman樹的變形:范式Huffman樹
4.范式Huffman樹
請看下節
總結
以上是生活随笔為你收集整理的基于LZ77算法的文件解压缩项目缺陷分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于LZ77算法的文件压缩收尾
- 下一篇: 基于Huffman算法和LZ77算法的文