前段時間研究了一下哈夫曼樹,也知道了其主要應用是哈夫曼編碼,那麼我想既然有編碼那麼我們是否可以利用這點來實現乙個檔案壓縮呢?答案是可以的,而且我已經實現了,這裡我就不將**放在下面了,下面我就說一下主要思路吧
1.統計:首先讀取乙個檔案,統計出256個字元中各個字元出現的次數以及字元出現的總數
2.建樹:按照字元出現的次數,並以次數作為權值建立哈夫曼編碼樹;建好樹後找出各個字元的編碼
3.壓縮:再次讀取檔案,按照該字元對應的編碼壓縮檔案
4.加工:將檔案的長度,檔案中各個字元以及它出現的次數寫進配置檔案中
5.解壓:利用壓縮檔案和配置檔案恢復出原檔案
6.測試:首先觀察解壓的檔案和原檔案是否相同,再通過beyond compare軟體進行對比,驗證程式的正確性
步驟大概就是以上五步,但是這裡包含的細節卻遠不止那些,其中的問題具體如下:
(1).為什麼要使用配置檔案呢,不使用不照樣能行嗎?
對於配置檔案的使用,我要說明一下原因。首先我們是將字元對應的編碼轉化為位,在unsigned char中填充位,填滿後就寫入到壓縮檔案中。
問題1:最後乙個位元組是不是很有可能沒有填滿,我們該如何判斷他是否填滿以及填了幾個字元的編碼?
問題2:若我依次壓縮一些檔案,壓縮完後再去解壓,那麼你的編碼此時已經沒有了,你該怎麼解壓呢?
上面的問題的解決方法就是通過配置檔案,假如我們要壓縮的檔案叫做***,那麼我們可以生成乙個***.config的配置檔案,在該配置檔案中寫入《檔案的總長度》(恢復時知道應該應該恢復多少個字元),(字元以及期出現的次數,用於解壓時重建哈夫曼樹),利用乙個配置檔案上述的問題就很好解決了。
(2).在檔案恢復的時候需要注意哪些問題呢?
有些特殊的字元的處理需要好好注意一下,比如 '\n',我的程式中有乙個函式就是讀取一行字元,但是若是該字元本身就是'\n'呢,我們寫入的的char就是\n呢?那麼我們就比較棘手了,對於這個問題,我們千萬不能漏掉,否則就不能恢復出原來的檔案。讀取配置檔案的時候若讀到』\n『則說明該字元就是'\n',應該繼續讀取它的次數。
另乙個問題就是需要注意機器的儲存方式,x86架構的機器的儲存方式是小端儲存,所以在存放的時候需要注意一下這個特性
其實是沒有影響的,因為移位的操作是根據高位和低位進行的
最後解壓的時候我們需要利用哈夫曼樹來找到對應的編碼,具體方法不好講解清楚,我畫了乙個圖,可以幫助理解:
(3).其他的問題
其他的問題都是寫小問題,例如我們在該專案中使用到了heap,huffmantree等等,而且都是使用模板實現的,所以在模板的推演,以及模板引數等等需要注意,例如:在實現堆的時候,我們可以通過模板引數compare的行為(過載operator())決定最終建立的堆是最大堆還是最小堆。
我使用了乙個測試用例作為說明,原檔案為「aacccceeeeefffffff」(名為 input),經過壓縮(input.huffman),解壓後(output.uncompress)的檔案的內容如下:
為了更進一步說明解壓後的檔案與原檔案是相同的,我使用了beyond compare 軟體將兩者進行對比,看是否相同,結果如下:
以上就是哈夫曼編碼實現檔案壓縮與解壓的過程,
以上就是哈夫曼編碼實現檔案壓縮與解壓的過程
專案 檔案壓縮與解壓縮
專案簡介 專案實現 pragma once include include using namespace std template struct less template struct greater templatestruct less template class heap heap t ...
測試小專案 檔案壓縮
磁碟空間不足,需要壓縮,解壓縮檔案 完成所有型別檔案的壓縮和解壓縮 功能需求 效能需求 安全需求 易用性需求 介面需求 相容性需求 需求核審 需求測試 測試設計中進行需求測試 需求測試要素 正確性,必要性,完整性,一致性 冒煙測試 版本測試中的資訊傳遞 修改內容,配置管理 根據測試用例執行測試 缺陷...
檔案壓縮原理
tom harris 或stuffit 這樣的程式來展開檔案,將其復原到原始大小。如果一切正常,展開的檔案與壓縮前的原始檔案將完全相同。乍一聽好像很神秘 您是怎樣減少位元和位元組的數量並將它們原封不動地還原回去的呢?等一切水落石出之後,您會發現這個過程背後的基本理念其實非常簡單明瞭。在本文中,我們將...