文件压缩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可以忽略。

原文地址:https://www.cnblogs.com/shy0322/p/9245178.html