文件的壓縮與解壓
專注于為中小企業(yè)提供成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)高明免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了1000+企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。u 開發(fā)環(huán)境:vs2013
u 開發(fā)技術(shù):vector、堆、哈夫曼樹、文件部分函數(shù)的操作
u 項(xiàng)目描述:文件壓縮是把一個(gè)占內(nèi)存比較大的文件壓縮成為一個(gè)占內(nèi)存比較小的文件,節(jié)省了磁盤的空 間,傳輸時(shí)也比較方便。解壓是把壓縮的文件還原成原來的文件,讀寫比較方便。
√可以壓縮與解壓小文件,也可以壓縮與解壓大文件。
√ 在Debug下,壓縮和解壓6M左右文件,需要25s左右,在Release下,需要2s左右。
√ 有配置文件,壓縮開發(fā)技術(shù):vector、堆、哈夫曼樹、文件部分函數(shù)的操作
u 遇到的問題:√ 在壓縮過程中不夠8位會補(bǔ)零,但在解壓過程中會把零讀出來,這樣就不對了。為了解決 這個(gè)問題。我在解壓過程中定義了一個(gè)總長度,它寫入一個(gè)字符,總長度就減1,當(dāng)長度 減為0,就不進(jìn)去了。
√ 有時(shí)解壓大文件時(shí),字?jǐn)?shù)不想等。于是我就把’w’換成了’wb’,把’r'換了’rb’因 為用文本模式打開時(shí),遇到’\n’,會多加’\r’,但用二進(jìn)制模式打開就不會有這樣的 問題。
√ 有時(shí)讀大文件時(shí),會讀不全。因此我就把EOF換成了feof。因?yàn)镋OF是以-1為結(jié)束標(biāo)志 的,但文件中出現(xiàn)-1它就不會讀下去了。如果換成feof的話,它是以“文件結(jié)束”為標(biāo) 志。這樣就不會出現(xiàn)讀不完的情況。
compress.h中
#ifndef __Compress_H_ #define __Compress_H_ #include <string> typedef long long LongType; struct CharInfo { unsigned char _ch;//字符 LongType _count;//出現(xiàn)次數(shù) string _code;//哈夫曼編碼 CharInfo(unsigned char ch = '0') :_ch(ch) , _count(0) , _code("") {} CharInfo(LongType count) :_count(count) , _ch(0) , _code("") {} //重載運(yùn)算符“>” bool operator >(const CharInfo& com)const { return _count > com._count; } //重載運(yùn)算符“!=” bool operator !=(CharInfo com)const { return _count != com._count; } //重載運(yùn)算符“+” CharInfo operator+(const CharInfo& com)const { return CharInfo(_count + com._count); } }; class FileCompress { public: //壓縮 FileCompress() { for (size_t i = 0; i < 256; i++) { _info[i]._ch = i; } } void Compress(const char* file) { //讀取文件 FILE *fout = fopen(file, "rb"); unsigned char ch = 0; assert(fout); //統(tǒng)計(jì)每個(gè)字符出現(xiàn)的次數(shù) ch = fgetc(fout); while (!feof(fout)) { _info[(unsigned char)ch]._count++; ch = fgetc(fout); } //用次數(shù)建立哈夫曼樹 const CharInfo invalid((unsigned char)0); HaffmanTree<CharInfo> tree(_info, 256,invalid); //生成哈夫曼編碼 string tmp; _CreateHaffmanCode(tree.GetRoot(), tmp); //壓縮 fseek(fout, 0, SEEK_SET);//從文件的首字符開始壓縮 //壓縮后的文件名 string comfile = file; comfile += ".haffman"; FILE *fin = fopen(comfile.c_str(), "wb"); assert(fin); unsigned char value = 0; size_t index = 0;//標(biāo)記當(dāng)前位 ch = fgetc(fout); while (!feof(fout)) { string code = _info[ch]._code; for (size_t i = 0; i < code.size(); i++) { if (code[i] == '1') { value <<= 1; value |= 1; } else { value <<= 1; } //滿8個(gè)字節(jié),將其寫入到壓縮文件中 if (++index == 8) { fputc(value, fin); value = 0; index = 0; } } ch = fgetc(fout); } //如果寫入完,value 沒有寫滿8位,把剩余的壓入壓縮文件中 if (index != 0) { value <<= (8 - index); fputc(value, fin); } //配置文件 string configfile = file; configfile += ".config"; FILE* finfo = fopen(configfile.c_str(), "wb"); assert(finfo); //將字符的總個(gè)數(shù)寫進(jìn)配置文件 char infostr[32]; //將出現(xiàn)的字符以及次數(shù)寫進(jìn)配置文件 string str; for (size_t j = 0; j < 256; j++) { if (_info[j]._count > 0) { str.push_back((unsigned char)j); str.push_back(','); _itoa(_info[j]._count, infostr, 10); str += infostr; fputs(str.c_str(), finfo); fputc('\n', finfo); str.clear(); } } fclose(fout); fclose(fin); fclose(finfo); } //解壓 void UnCompress(const char *file) { unsigned char ch = 0; string fconfig = file; fconfig += ".config"; //讀壓縮文件 FILE* fout = fopen(fconfig.c_str(), "rb"); assert(fout); string tmp; //字符出現(xiàn)的次數(shù) while (ReadLine(fout, tmp)) { if (!tmp.empty()) { //那到字符 ch = tmp[0]; //獲取字符的次數(shù) _info[(unsigned char)ch]._count = atoi(tmp.substr(2).c_str()); tmp.clear(); } else { tmp = '\n'; } } //重建哈夫曼樹 CharInfo invalid((unsigned char)0); HaffmanTree<CharInfo> h(_info, 256, invalid); HaffmanTreeNode<CharInfo>*root = h.GetRoot(); //解壓 string output = file; output += ".uncom"; FILE* fin = fopen(output.c_str(), "wb"); assert(fin); //根據(jù)壓縮文件,還原文件 string Haffmanfile = file; Haffmanfile += ".haffman"; FILE* fcom = fopen(Haffmanfile.c_str(), "rb"); assert(fcom); HaffmanTreeNode<CharInfo>*cur = root; ch = fgetc(fcom); int pos = 8; LongType len = root->_weight._count; while (len > 0) { while (cur->_left &&cur->_right) { if (pos == 0) { ch = fgetc(fcom); pos = 8; } --pos; //與1,走右樹 if (ch&(1 << pos)) { cur = cur->_right; } //與0,走左樹 else { cur = cur->_left; } } if (cur) { fputc(cur->_weight._ch, fin);//寫進(jìn)解壓文件 cur = root; } --len; } fclose(fout); fclose(fin); fclose(fcom); } protected: //創(chuàng)建哈夫曼編碼 void _CreateHaffmanCode(HaffmanTreeNode<CharInfo>*root, string tmp) { //判空 if (root == NULL) { return; } if (root->_left == NULL&&root->_right == NULL) { //找到下標(biāo),把編碼寫到_code中 int index = (root->_weight)._ch; _info[index]._code = tmp; } else { //左樹寫0 if (root->_left) { tmp.push_back('0'); _CreateHaffmanCode(root->_left, tmp); tmp.pop_back(); } //右樹寫1 if (root->_right) { tmp.push_back('1'); _CreateHaffmanCode(root->_right, tmp); tmp.pop_back(); } } } //讀一行 bool ReadLine(FILE* file, string& tmp) { assert(file); char ch = fgetc(file); if (feof(file)) { return false; } while (ch != '\n') { tmp += ch; ch = fgetc(file); } return true; } protected: CharInfo _info[256]; }; #endif //__Compress_H_
HaffmanTree.h中
#ifndef __HaffmanTree_H_ #define __HaffmanTree_H_ #include "Heap.h" template<class T> struct HaffmanTreeNode { typedef HaffmanTreeNode<T> Node; T _weight; Node* _left; Node* _right; HaffmanTreeNode(const T& weight) :_weight(weight) , _left(NULL) , _right(NULL) {} }; template<class T> class HaffmanTree { typedef HaffmanTreeNode<T> Node; public: HaffmanTree() :_root(NULL) {} HaffmanTree(const T* arr, size_t size) { _root = _Create(arr, size); } //構(gòu)造函數(shù) HaffmanTree(const T* arr, size_t size, const T& invalid) { _root = _Create(arr, size, invalid); } ~HaffmanTree() { if (_root) { _Destroy(_root); } } Node* GetRoot() { return _root; } protected: //創(chuàng)建哈夫曼樹 Node* _Create(const T* arr, size_t size, const T& invalid) { struct compare { bool operator ()(const Node *left, const Node *right) { return left->_weight > right->_weight; } }; Heap<Node*,compare> _heap; //把值放到vector中 for (size_t i = 0; i < size; ++i) { if (arr[i] != invalid) { Node *tmp = new Node(arr[i]); _heap.Push(tmp); } } //構(gòu)造哈夫曼樹 while (_heap.Size() > 1) { Node *left = _heap.Top(); _heap.Pop(); Node*right = _heap.Top(); _heap.Pop(); Node *parent = new Node(left->_weight + right->_weight); parent->_left = left; parent->_right = right; _heap.Push(parent); } return _heap.Top(); } //釋放節(jié)點(diǎn) void _Destroy(Node* root) { if (root->_left == NULL && root->_right == NULL) { delete root; root = NULL; } else { _Destroy(root->_left); _Destroy(root->_right); } } private: Node *_root; }; #endif //__HaffmanTree_H_
Heap.h中
#ifndef __Heap_H_ #define __Heap_H_ #include<vector> #include<assert.h> template<class T> //比較器 class Less { public: bool operator() (const T& left, const T& right) { return left > right; } }; template<class T> class Greater { public: bool operator() (const T& left, const T& right) { return left < right; } }; template<class T, class Compare = Less<T> > class Heap { public: //構(gòu)造函數(shù) Heap() :_arr(NULL) {} Heap(const T* arr, int size) { assert(arr); _arr.reserve(size); for (int i = 0; i < size; i++) { _arr.push_back(arr[i]); } int begin = _arr.size() / 2 - 1; while (begin >= 0) { _AdjustDown(begin); begin--; } } //拷貝構(gòu)造 Heap(vector<T>& s) { _arr = s; int begin = _arr.size() / 2 - 1; while (begin >= 0) { _AdjustDown(begin); begin--; } } void Push(const T& x) { _arr.push_back(x); int begin = _arr.size(); _AdjustUp(begin); } void Pop() { _arr[0] = _arr[_arr.size() - 1]; _arr.pop_back(); _AdjustDown(0); } void Clear() { _arr.clear(); } bool Empty() { return _arr.empty(); } T& Top() { if (!Empty()) { return _arr[0]; } exit(1); } size_t Size() { return _arr.size(); } protected: //下調(diào) void _AdjustDown(int parent) { // 從根節(jié)點(diǎn)向下調(diào)整 int size = _arr.size(); int left = parent * 2 + 1; int right = left + 1; int key = left; while (left < size) {//Compare()仿函數(shù) //if (right < size && array[left] > array[right]) if (right < size && Compare()(_arr[left], _arr[right])) //右邊小 { key = right; } else { key = left; } //if ((array[key] > array[parent])) if (Compare()(_arr[key], _arr[parent])) { break; } //else if (array[parent] > array[key]) else if (Compare()(_arr[parent], _arr[key])) //左邊小 { swap(_arr[key], _arr[parent]); } parent = key; left = parent * 2 + 1; right = left + 1; } } //上調(diào) void _AdjustUp(int child) { //從葉子節(jié)點(diǎn)或子節(jié)點(diǎn)向上調(diào)整 int size = _arr.size(); if (size == 0 || size == 1) { return; } int parent = (child - 2) / 2; int left = parent * 2 + 1; int right = left + 1; int key = 0; while (parent >= 0) { //if (right < size && array[left] > array[right]) if (right < size && Compare()(_arr[left], _arr[right])) { key = right; } else { key = left; } //if (array[parent] > array[key]) if (Compare()(_arr[parent], _arr[key])) { swap(_arr[parent], _arr[key]); } else { break; } if (parent == 0) { break; } parent = (parent - 1) / 2; left = parent * 2 + 1; right = left + 1; } } private: vector<T> _arr; }; #endif //__Heap_H_
test.cpp中
#define _CRT_SECURE_NO_WARNINGS 1 #include<time.h> #include <iostream> using namespace std; #include "HaffmanTree.h" #include "Compress.h" void Test() { double t1; double t2; FileCompress f; //f.Compress("input.txt"); f.Compress("mnt.txt"); t1 = clock(); printf("壓縮文件需要的時(shí)間: %f s \n", t1 / CLOCKS_PER_SEC); //f.UnCompress("input.txt"); f.UnCompress("mnt.txt"); t2 = clock(); printf("解壓縮文件需要的時(shí)間: %f s \n", t2 / CLOCKS_PER_SEC); } int main() { Test(); system("pause"); return 0; }
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。
網(wǎng)站題目:文件壓縮與解壓-創(chuàng)新互聯(lián)
文章源于:http://jinyejixie.com/article28/dipejp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供ChatGPT、Google、企業(yè)建站、全網(wǎng)營銷推廣、軟件開發(fā)、手機(jī)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容