文件压缩day4——针对单个文件压缩和解压全体解决。
上次说到还留有两个问题。
这次我们先处理第一问:
为什么解压到一半就停止的情况,问题在于我们解压部分的函数的循环判断。
我们知道,我们用哈夫曼码形成字符压入压缩文件,但是,哈夫曼码极有可能会组成11111111也就是-1,即很有可能达成循环终止条件造成退出,所以我们需要适当修改一下代码——
1 while (count > 0) 2 { 3 _c = f_in.get(); 4 for (size_t i = 0; i < 8; i++) 5 { 6 if ((_c & 1) == 0)//'1' 7 cur = cur->_left; 8 else //'0' 9 cur = cur->_right; 10 //叶子 11 if (cur->_left == NULL && cur->_right == NULL) 12 { 13 f_out.put(cur->_val._ch); 14 cur = MyHuffman.GetRoot(); 15 --count; 16 if (count <= 0) 17 break; 18 } 19 _c >>= 1; 20 } 21 }
我们要注意的是,不能写成count != 0 (当然如果在代码中加了一个break的话,那就问题不大了),因为很有可能解完了,因为后续还有0,没有退出for的那层循环,接着解导致死循环(程序崩溃)。
我们现在来探讨第二个问题:要将压缩和解压缩功能分开,为何解压缩不成功?
其实很好理解,你在解压缩时,你的类对象重新构造,哈希表里什么都没有,自然不可能解压缩成功啦,所以我们要做的,就是在压缩时将哈希表也压缩进来,而解压缩时,先提取哈希表,然后再解压缩,看如下代码——
1 //要将哈希表的重要内容都写到解压文件中 2 //千万注意一定要置零,因为最初的情况下!!!都是随机数 3 //解压时需要以0为判断!!! 4 5 //只要遇到一个在哈希表中存在个数的,就可以放进压缩文件中!!! 6 ImpoInfo buf; 7 memset(&buf, 0x00, sizeof(ImpoInfo)); 8 9 for (size_t i = 0; i < 256; ++i) 10 { 11 if (_hashInfos[i]._count != 0) 12 { 13 buf._ch = _hashInfos[i]._ch; 14 buf._count = _hashInfos[i]._count; 15 16 f_out.write(reinterpret_cast<char*>(&buf), sizeof(ImpoInfo)); 17 memset(&buf, 0x00, sizeof(ImpoInfo)); 18 } 19 } 20 //最后以一个放了-1的表示终止!!! 21 buf._count = -1; 22 23 f_out.write(reinterpret_cast<char*>(&buf), sizeof(ImpoInfo));
1 //读哈希表重要信息 2 ImpoInfo buf; 3 memset(&buf, 0x00, sizeof(ImpoInfo));//可置可不置 4 5 f_in.read(reinterpret_cast<char*>(&buf), sizeof(ImpoInfo)); 6 7 while (buf._count != -1) 8 { 9 _hashInfos[static_cast<unsigned char>(buf._ch)]._count = buf._count; 10 memset(&buf, 0x00, sizeof(ImpoInfo)); 11 12 f_in.read(reinterpret_cast<char*>(&buf), sizeof(ImpoInfo)); 13 }
需要特别注意,拷贝哈希表时是用二进制写入和二进制读出的,因为二进制是完完全全的拷贝过去,虽然用户不可视,但是信息保存的比较好。
ps:vs2013在创建文件时,要用上构造函数的第二个参数,并且加上std::ios::out | std::ios::binary 或std::ios::in | std::ios::binary。
vs2008可以忽略。