Repository navigation
Expand file tree
/
Copy pathHuffmanCompress.cpp
More file actions
275 lines (238 loc) · 6.06 KB
/
Copy pathHuffmanCompress.cpp
File metadata and controls
275 lines (238 loc) · 6.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
#include <queue>
#include <assert.h>
#include "HuffmanCompress.h"
#include "HuffmanTree.hpp"
using namespace std;
bool CharInfo::operator>(const CharInfo& c) const
{
return _charCount > c._charCount;
}
CharInfo CharInfo::operator+(const CharInfo& c) const
{
CharInfo temp;
temp._charCount = _charCount + c._charCount;
return temp;
}
HuffmanCompress::HuffmanCompress()
{
_charInfo.resize(256);
for (int i = 0; i < 256; i++) {
//vextor中的每个下标中的字符都对应自己的ASCII
_charInfo[i]._char = i;
}
}
void HuffmanCompress::WriteHead(FILE* fOut, const std::string& filepath)
{
assert(fOut != nullptr);
string headInfo = ""; //头信息
//写入后缀
string fileSuffix = filepath.substr(filepath.rfind('.'));
headInfo += fileSuffix;
headInfo += '\n';
size_t charTypeCount = 0; //字符类型数,也就是行数
string charCount = ""; //每个字符出现的次数和字符
for (size_t i = 0; i < _charInfo.size(); i++) {
if (_charInfo[i]._charCount != 0) {
charTypeCount++;
charCount += _charInfo[i]._char;
charCount += ',';
char temp[32] = { 0 };
_itoa(_charInfo[i]._charCount, temp, 10);
charCount += temp;
charCount += '\n';
}
}
//写入字符类型数
char charTypeNum[32] = { 0 };
_itoa(charTypeCount, charTypeNum, 10);
headInfo += charTypeNum;
headInfo += '\n';
//写入字符信息
headInfo += charCount;
fwrite(headInfo.c_str(), 1, headInfo.size(), fOut);
}
std::string HuffmanCompress::Compress(const string& filepath)
{
FILE* fIn = fopen(filepath.c_str(), "rb");
if (fIn == nullptr) {
cout << "error for fin!" << endl;
exit(0);
}
while (1) {
//1. 遍历文件,获取每个字符出现的次数
unsigned char *tempbuf = new unsigned char [HUFFMANSIZE];
//从文件中读取待压缩信息
size_t rdSize = fread(tempbuf, 1, HUFFMANSIZE, fIn);
if (rdSize == 0) {
//如果读到的信息为0 说明读完了
break;
}
//遍历 并且保存数据
for (size_t i = 0; i < rdSize; i++) {
//字符读应的计数器加一
//tempbuf[i] 是取到的字符 直接用ASCII 就是对于的下标
_charInfo[tempbuf[i]]._charCount++;
}
}
string headCharInfo;
//创建huffman树
//在_charInfo中共保存了256个字符的信息
//创建huffman节点应该是给出现过的创建,因此应该进行一次判断
//因为每次都需要取两个最小的 因此 直接将它们放在优先级队列中
//直接创建成小树 取就可以
HuffmanTree<CharInfo> huffmantree;
huffmantree.CreateHuffmanTree(_charInfo);
//得到字符的编码
huffmantree.GetHuffmanCode(_charInfo);
//打开压缩文件
string filename = filepath.substr(0, filepath.rfind('.')) + ".hip";
FILE* fOut = fopen(filename.c_str(), "wb");
if (fIn == nullptr) {
cout << "error for fout!" << endl;
exit(0);
}
//写入头信息
WriteHead(fOut, filepath);
//从头再读取文件,转换成压缩文件
fseek(fIn, 0, SEEK_SET);
unsigned char code = 0; //记录写入的编码
size_t leftCount = 0; //记录左移次数
//压缩
while (1) {
unsigned char* inbuffer = new unsigned char[HUFFMANSIZE];
unsigned char* outbuffer = new unsigned char[HUFFMANSIZE];
size_t outbufferpos = 0;
//char outBuf[1024] = { 0 };
size_t rdSize = fread(inbuffer, 1, HUFFMANSIZE, fIn);
if (rdSize == 0) {
break;
}
for (size_t i = 0; i < rdSize; ++i) {
//遇见字符 修改后写入文件
size_t j = 0;
while (j < _charInfo[inbuffer[i]]._huffmanCode.size()) {
//将对应字符的编码全部写入
//当code中没有写满时,进行写入
leftCount++;
code <<= 1;
//00000000
if (_charInfo[inbuffer[i]]._huffmanCode[j] == '1') {
code |= 1;
}
j++;
if (leftCount == 8) {
/*fputc(code, fOut);*/
outbuffer[outbufferpos++] = code;
if (outbufferpos == HUFFMANSIZE) {
fwrite(outbuffer, outbufferpos, 1, fOut);
outbufferpos = 0;
}
leftCount = 0;
code = 0;
}
}
}
fwrite(outbuffer, outbufferpos, 1, fOut);
}
if (leftCount > 0 && leftCount <= 8) {
code <<= (8 - leftCount);
fputc(code, fOut);
}
//关闭文件流 释放树
fclose(fIn);
fclose(fOut);
return filename;
}
void HuffmanCompress::GetLine(FILE* fIn, std::string& inbuffer)
{
assert(fIn != nullptr);
while (!feof(fIn)) {
unsigned char c = fgetc(fIn);
if (c == '\n' || feof(fIn)) {
return;
}
inbuffer += c;
}
}
std::string HuffmanCompress::UnCompress(const std::string & filepath)
{
//解压缩,先读取文件前面的信息
if (filepath.substr(filepath.rfind('.')) != ".hip") {
cout << "error for file type" << endl;
exit(0);
}
FILE* fIn = fopen(filepath.c_str(), "rb");
if (fIn == nullptr) {
cout << "error for fIn" << endl;
exit(0);
}
//读取后缀信息
string fileSuffix = "";
GetLine(fIn, fileSuffix);
//读取字符类型数
string charTypeNum_s = "";
GetLine(fIn, charTypeNum_s);
size_t charTypeNum = atoi(charTypeNum_s.c_str());
//读取字符信息,并创建Huffman树
for (size_t i = 0; i < charTypeNum; i++) {
string getCharInfo = "";
GetLine(fIn, getCharInfo);
if (getCharInfo.empty()) {
getCharInfo += '\n';
GetLine(fIn, getCharInfo);
}
_charInfo[(unsigned char)getCharInfo[0]]._charCount = atoi(getCharInfo.c_str() + 2);
}
//创建Huffman树
HuffmanTree<CharInfo> huffmantree;
huffmantree.CreateHuffmanTree(_charInfo);
//解压缩
//读取文件名和后缀
string filename = filepath.substr(0, filepath.rfind('.')) + "UnCompress";
filename += fileSuffix;
FILE* fOut = fopen(filename.c_str(), "wb");
if (fOut == nullptr) {
cout << "error for fOut" << endl;
exit(0);
}
HuffmanNode<CharInfo>* cur = huffmantree.GetRoot();
//表示字符数
size_t charNum = cur->_weight._charCount;
while (1) {
unsigned char inbuffer[1024] = { 0 };
size_t reSize = fread(inbuffer, 1, 1024, fIn);
if (reSize == 0) {
break;
}
for (size_t i = 0; i < reSize; i++) {
size_t leftCount = 7;
for (size_t j = 0; j < 8; j++) {
if (inbuffer[i] & (1 << leftCount)) {
//1000 0000
cur = cur->_rightNode;
}
else {
cur = cur->_leftNode;
}
if (cur->_leftNode == nullptr && cur->_rightNode == nullptr) {
fputc(cur->_weight._char, fOut);
//fputc(cur->_weight._char, stdout);
cur = huffmantree.GetRoot();
charNum--;
if (charNum == 0) {
break;
}
}
leftCount--;
}
}
}
//关闭文件流 释放树
fclose(fIn);
fclose(fOut);
return filename;
}
HuffmanCompress::~HuffmanCompress()
{
return;
}