一个用C实现的哈弗曼编码实现文件压缩和解压

来源:互联网 发布:c语言调用大漠插件 编辑:程序博客网 时间:2024/06/11 03:34

    将压缩和解压放在了一个程序里面,并加入了进度显示功能。

    并不完善,因为使用'\b'回退符来达到进度的数字能够变化,可是在需要操作的文件较小时会闪动比较严重,还会消耗多余的资源在显示上面,所以执行效率并不算高,可能在学会其他知识,比如图形化界面时我会再来改进它。

    其他内容在旧版中有写,说多了都是泪 :http://blog.csdn.net/tookkke/article/details/50529838

[cpp] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. #include <cstdio>                                     /************/  
  2. #include <cstring>                                    /*    by    */  
  3. #include <iostream>                                   /*   kkke   */  
  4. #include <algorithm>                                  /************/  
  5. #include <queue>                                                       //2016.1.24  
  6. #include <conio.h>  
  7.   
  8. #define MAX_WORD (65536)  
  9. #define MAX_BYTE (256)  
  10.   
  11. using namespace std;  
  12.   
  13. typedef unsigned char BYTE;  
  14. typedef unsigned short WORD;  
  15. typedef unsigned long DWORD;  
  16. typedef unsigned long long ULL;  
  17.   
  18. char in_file_name[80];  
  19. char out_file_name[80];  
  20. int cnt[MAX_BYTE*2];//number of each BYTE  
  21. int filesize;  
  22. ULL bit_cnt;  
  23. int kkke[MAX_BYTE][MAX_BYTE];  
  24. int kkke1[MAX_BYTE];  
  25. int hehe[MAX_BYTE];  
  26.   
  27. const int tree_size=MAX_BYTE*2;  
  28. struct the_tree{  
  29.     int son[2];  
  30. }tree[MAX_BYTE*2];//root is 1  
  31.   
  32. struct cmp{  
  33.     bool operator()(int a,int b)  
  34.     {  
  35.         return cnt[a]>cnt[b];  
  36.     }  
  37. };  
  38.   
  39. void read_data();  
  40. void build_tree();  
  41. void dfs(int k,int b);  
  42. void output();  
  43.   
  44. void kdecompress()  
  45. {  
  46.     system("cls");  
  47.     printf("解压\n");  
  48.     printf("请输入待解压文件名(不加.kcps):");  
  49.     scanf("%s",in_file_name);  
  50.     printf("请选择 输出文件名(会覆盖重名文件):\n");  
  51.     printf("    1. %s\n",in_file_name);  
  52.     printf("    2. 手动输入\n");  
  53.     char c;  
  54.     while((c=getch())!='1'&&c!='2');  
  55.     if(c=='1')strcpy(out_file_name,in_file_name);  
  56.     else  
  57.     {  
  58.         printf("请输入输出文件名:");  
  59.         scanf("%s",out_file_name);  
  60.     }  
  61.     strcat(in_file_name,".kcps");  
  62.     printf("将会生成 %s\n",out_file_name);  
  63.     printf("    取消: ESC\n");  
  64.     printf("    确认: 回车\n");  
  65.     while((c=getch())!=13&&c!=27);  
  66.     if(c==27)return;  
  67.       
  68.     FILE *infp=fopen(in_file_name,"rb");  
  69.     if(infp==NULL)  
  70.     {  
  71.         printf("待解压文件 %s 打开失败\n",in_file_name);  
  72.         exit(1);  
  73.     }  
  74.     FILE *outfp=fopen(out_file_name,"wb");  
  75.     if(outfp==NULL)  
  76.     {  
  77.         printf("解压文件 %s 创建失败\n",out_file_name);  
  78.         exit(1);  
  79.     }  
  80.       
  81.     for(int i=1;i<tree_size;i++)fread(&tree[i],sizeof(tree[i]),1,infp);  
  82.     fread(&bit_cnt,sizeof(bit_cnt),1,infp);  
  83.       
  84.     BYTE a1;  
  85.     int a2=8;  
  86.     int nown=1;  
  87.     int b=0;  
  88.     system("cls");  
  89.     printf("正在解压文件... %3d.%02d%%",b/100,b%100);  
  90.     for(long long i=1;i<=bit_cnt;i++)  
  91.     {  
  92.         if(a2==8)  
  93.         {  
  94.             a2=0;  
  95.             fread(&a1,sizeof(a1),1,infp);  
  96.         }  
  97.         if(a1&((BYTE)1<<a2))nown=tree[nown].son[1];  
  98.         else nown=tree[nown].son[0];  
  99.         if(nown>=MAX_BYTE)  
  100.         {  
  101.             BYTE aa=nown-MAX_BYTE;  
  102.             fwrite(&aa,sizeof(aa),1,outfp);  
  103.             nown=1;  
  104.         }  
  105.         a2++;  
  106.         if(b==i*10000/bit_cnt)continue;  
  107.         b=i*10000/bit_cnt;  
  108.         for(int k=0;k<7;k++)putchar('\b');  
  109.         printf("%3d.%02d%%",b/100,b%100);  
  110.     }  
  111.     putchar('\n');  
  112.     if(fclose(infp))  
  113.     {  
  114.         printf("关闭输入文件 %s 失败\n",in_file_name);  
  115.         exit(1);  
  116.     }  
  117.     if(fclose(outfp))  
  118.     {  
  119.         printf("关闭输出文件 %s 失败\n",out_file_name);  
  120.         exit(1);  
  121.     }  
  122.     system("pause");  
  123. }  
  124.   
  125. void kcompress()  
  126. {  
  127.     system("cls");  
  128.     printf("压缩\n");  
  129.     printf("请输入待压缩文件名:");  
  130.     scanf("%s",in_file_name);  
  131.     printf("请选择 输出文件名(会覆盖重名文件):\n");  
  132.     printf("    1. %s.kcps\n",in_file_name);  
  133.     printf("    2. 手动输入(.kcps)\n");  
  134.     char c;  
  135.     while((c=getch())!='1'&&c!='2');  
  136.     if(c=='1')strcpy(out_file_name,in_file_name);  
  137.     else  
  138.     {  
  139.         printf("请输入输出文件名:");  
  140.         scanf("%s",out_file_name);  
  141.     }  
  142.     strcat(out_file_name,".kcps");  
  143.     printf("将会生成 %s\n",out_file_name);  
  144.     printf("    取消: ESC\n");  
  145.     printf("    确认: 回车\n");  
  146.     while((c=getch())!=13&&c!=27);  
  147.     if(c==27)return;  
  148.       
  149.     read_data();  
  150.     build_tree();  
  151.     dfs(1,0);  
  152.     output();  
  153.     system("pause");  
  154. }  
  155.   
  156. int main()  
  157. {  
  158.     while(true)  
  159.     {  
  160.         system("cls");  
  161.         printf("@kkke随便写写的压缩程序:\n");  
  162.         printf("请置于待操作文件同一文件夹\n");  
  163.         printf("选择    1. 压缩\n");  
  164.         printf("        2. 解压\n");  
  165.         char c;  
  166.         while((c=getch())!='1'&&c!='2');  
  167.         if(c=='1')  
  168.         {  
  169.             printf("已选择 压缩\n");  
  170.             printf("    取消: ESC\n");  
  171.             printf("    确认: 回车\n");  
  172.             while((c=getch())!=13&&c!=27);  
  173.             if(c==27)continue;  
  174.             kcompress();  
  175.         }  
  176.         else  
  177.         {  
  178.             printf("已选择 解压\n");  
  179.             printf("    取消: ESC\n");  
  180.             printf("    确认: 回车\n");  
  181.             while((c=getch())!=13&&c!=27);  
  182.             if(c==27)continue;  
  183.             kdecompress();  
  184.         }  
  185.     }  
  186.     return 0;  
  187. }  
  188.   
  189. void output()  
  190. {  
  191.     FILE *infp=fopen(in_file_name,"rb");  
  192.     if(infp==NULL)  
  193.     {  
  194.         printf("待压缩文件 %s 打开失败\n",in_file_name);  
  195.         exit(1);  
  196.     }  
  197.     FILE *outfp=fopen(out_file_name,"wb");  
  198.     if(outfp==NULL)  
  199.     {  
  200.         printf("压缩文件 %s 创建失败\n",out_file_name);  
  201.         exit(1);  
  202.     }  
  203.       
  204.     for(int i=1;i<tree_size;i++)fwrite(&tree[i],sizeof(tree[i]),1,outfp);  
  205.     bit_cnt=0ULL;  
  206.     for(int i=0;i<MAX_BYTE;i++)bit_cnt+=(ULL)hehe[i]*(ULL)cnt[i+MAX_BYTE];  
  207.     fwrite(&bit_cnt,sizeof(bit_cnt),1,outfp);  
  208.       
  209.     int b=0;  
  210.     system("cls");  
  211.     printf("生成文件总大小: %.3f KB\n",((double)bit_cnt+8.0*(double)sizeof(tree))/8192.0);  
  212.     printf("压缩率: %.3f%%\n",((double)bit_cnt+8.0*(double)sizeof(tree))/0.08/(double)filesize);  
  213.     printf("正在生成压缩文件... %3d.%02d%%",b/100,b%100);  
  214.       
  215.     BYTE a;  
  216.     BYTE a1=0;  
  217.     int a2=0;  
  218.     for(int i=1;i<=filesize;i++)  
  219.     {  
  220.         fread(&a,sizeof(a),1,infp);  
  221.         for(int j=0;j<hehe[a];j++)  
  222.         {  
  223.             if(kkke[a][j])a1|=((BYTE)1<<a2);  
  224.             a2++;  
  225.             if(a2==8)  
  226.             {  
  227.                 a2=0;  
  228.                 fwrite(&a1,sizeof(a1),1,outfp);  
  229.                 a1=0;  
  230.             }  
  231.         }  
  232.         if(b==(ULL)i*10000/filesize)continue;  
  233.         b=(ULL)i*10000/filesize;  
  234.         for(int k=0;k<7;k++)putchar('\b');  
  235.         printf("%3d.%02d%%",b/100,b%100);  
  236.     }  
  237.     putchar('\n');  
  238.     if(a2)fwrite(&a1,sizeof(a1),1,outfp);  
  239.     if(fclose(infp))  
  240.     {  
  241.         printf("关闭输入文件 %s 失败\n",in_file_name);  
  242.         exit(1);  
  243.     }  
  244.     if(fclose(outfp))  
  245.     {  
  246.         printf("关闭输出文件 %s 失败\n",out_file_name);  
  247.         exit(1);  
  248.     }  
  249. }  
  250.   
  251. void dfs(int k,int b)  
  252. {  
  253.     if(k>=MAX_BYTE)  
  254.     {  
  255.         k-=MAX_BYTE;  
  256.         for(int i=0;i<b;i++)kkke[k][i]=kkke1[i];  
  257.         hehe[k]=b;  
  258.     }  
  259.     else  
  260.     {  
  261.         kkke1[b]=0;  
  262.         dfs(tree[k].son[0],b+1);  
  263.         kkke1[b]=1;  
  264.         dfs(tree[k].son[1],b+1);  
  265.     }  
  266. }  
  267.   
  268. void build_tree()  
  269. {  
  270.     system("cls");  
  271.     printf("正在分析文件...\n");  
  272.     priority_queue<int,vector<int>,cmp>q;  
  273.     for(int i=MAX_BYTE+MAX_BYTE-1;i>=MAX_BYTE;i--)q.push(i);  
  274.     for(int i=MAX_BYTE-1;i;i--)  
  275.     {  
  276.         tree[i].son[0]=q.top();q.pop();  
  277.         tree[i].son[1]=q.top();q.pop();   
  278.         cnt[i]=cnt[tree[i].son[0]]+cnt[tree[i].son[1]];  
  279.         q.push(i);  
  280.     }  
  281. }  
  282.   
  283. void read_data()  
  284. {  
  285.     memset(cnt,0,sizeof(cnt));  
  286.     FILE *infp=fopen(in_file_name,"rb");  
  287.     if(infp==NULL)  
  288.     {  
  289.         printf("未找到待压缩文件\n");  
  290.         exit(1);  
  291.     }  
  292.     fseek(infp,0,SEEK_END);  
  293.     filesize=ftell(infp);  
  294.     fseek(infp,0,SEEK_SET);  
  295.     BYTE a;  
  296.     int b=0;  
  297.     system("cls");  
  298.     printf("文件总大小: %.3f KB\n",(double)filesize/1024.0);  
  299.     printf("正在读取文件... %3d.%02d%%",b/100,b%100);  
  300.     for(int i=1;i<=filesize;i++)  
  301.     {  
  302.         fread(&a,sizeof(a),1,infp);  
  303.         cnt[a+MAX_BYTE]++;  
  304.         if(b==(ULL)i*10000/filesize)continue;  
  305.         b=(ULL)i*10000/filesize;  
  306.         for(int k=0;k<7;k++)putchar('\b');  
  307.         printf("%3d.%02d%%",b/100,b%100);  
  308.     }  
  309.     if(fclose(infp))  
  310.     {  
  311.         printf("关闭输入文件失败\n");  
  312.         exit(1);  
  313.     }  
  314. }  

转载至

0 0