将压缩和解压放在了一个程序里面,并加入了进度显示功能。
并不完善,因为使用'\b'回退符来达到进度的数字能够变化,可是在需要操作的文件较小时会闪动比较严重,还会消耗多余的资源在显示上面,所以执行效率并不算高,可能在学会其他知识,比如图形化界面时我会再来改进它。
其他内容在旧版中有写,说多了都是泪 :http://blog.csdn.net/tookkke/article/details/50529838
#include <cstdio> /************/ #include <cstring> /* by */ #include <iostream> /* kkke */ #include <algorithm> /************/ #include <queue> //2016.1.24 #include <conio.h> #define MAX_WORD (65536) #define MAX_BYTE (256) using namespace std; typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; typedef unsigned long long ULL; char in_file_name[80]; char out_file_name[80]; int cnt[MAX_BYTE*2];//number of each BYTE int filesize; ULL bit_cnt; int kkke[MAX_BYTE][MAX_BYTE]; int kkke1[MAX_BYTE]; int hehe[MAX_BYTE]; const int tree_size=MAX_BYTE*2; struct the_tree{ int son[2]; }tree[MAX_BYTE*2];//root is 1 struct cmp{ bool operator()(int a,int b) { return cnt[a]>cnt[b]; } }; void read_data(); void build_tree(); void dfs(int k,int b); void output(); void kdecompress() { system("cls"); printf("解压\n"); printf("请输入待解压文件名(不加.kcps):"); scanf("%s",in_file_name); printf("请选择 输出文件名(会覆盖重名文件):\n"); printf(" 1. %s\n",in_file_name); printf(" 2. 手动输入\n"); char c; while((c=getch())!='1'&&c!='2'); if(c=='1')strcpy(out_file_name,in_file_name); else { printf("请输入输出文件名:"); scanf("%s",out_file_name); } strcat(in_file_name,".kcps"); printf("将会生成 %s\n",out_file_name); printf(" 取消: ESC\n"); printf(" 确认: 回车\n"); while((c=getch())!=13&&c!=27); if(c==27)return; FILE *infp=fopen(in_file_name,"rb"); if(infp==NULL) { printf("待解压文件 %s 打开失败\n",in_file_name); exit(1); } FILE *outfp=fopen(out_file_name,"wb"); if(outfp==NULL) { printf("解压文件 %s 创建失败\n",out_file_name); exit(1); } for(int i=1;i<tree_size;i++)fread(&tree[i],sizeof(tree[i]),1,infp); fread(&bit_cnt,sizeof(bit_cnt),1,infp); BYTE a1; int a2=8; int nown=1; int b=0; system("cls"); printf("正在解压文件... %3d.%02d%%",b/100,b%100); for(long long i=1;i<=bit_cnt;i++) { if(a2==8) { a2=0; fread(&a1,sizeof(a1),1,infp); } if(a1&((BYTE)1<<a2))nown=tree[nown].son[1]; else nown=tree[nown].son[0]; if(nown>=MAX_BYTE) { BYTE aa=nown-MAX_BYTE; fwrite(&aa,sizeof(aa),1,outfp); nown=1; } a2++; if(b==i*10000/bit_cnt)continue; b=i*10000/bit_cnt; for(int k=0;k<7;k++)putchar('\b'); printf("%3d.%02d%%",b/100,b%100); } putchar('\n'); if(fclose(infp)) { printf("关闭输入文件 %s 失败\n",in_file_name); exit(1); } if(fclose(outfp)) { printf("关闭输出文件 %s 失败\n",out_file_name); exit(1); } system("pause"); } void kcompress() { system("cls"); printf("压缩\n"); printf("请输入待压缩文件名:"); scanf("%s",in_file_name); printf("请选择 输出文件名(会覆盖重名文件):\n"); printf(" 1. %s.kcps\n",in_file_name); printf(" 2. 手动输入(.kcps)\n"); char c; while((c=getch())!='1'&&c!='2'); if(c=='1')strcpy(out_file_name,in_file_name); else { printf("请输入输出文件名:"); scanf("%s",out_file_name); } strcat(out_file_name,".kcps"); printf("将会生成 %s\n",out_file_name); printf(" 取消: ESC\n"); printf(" 确认: 回车\n"); while((c=getch())!=13&&c!=27); if(c==27)return; read_data(); build_tree(); dfs(1,0); output(); system("pause"); } int main() { while(true) { system("cls"); printf("@kkke随便写写的压缩程序:\n"); printf("请置于待操作文件同一文件夹\n"); printf("选择 1. 压缩\n"); printf(" 2. 解压\n"); char c; while((c=getch())!='1'&&c!='2'); if(c=='1') { printf("已选择 压缩\n"); printf(" 取消: ESC\n"); printf(" 确认: 回车\n"); while((c=getch())!=13&&c!=27); if(c==27)continue; kcompress(); } else { printf("已选择 解压\n"); printf(" 取消: ESC\n"); printf(" 确认: 回车\n"); while((c=getch())!=13&&c!=27); if(c==27)continue; kdecompress(); } } return 0; } void output() { FILE *infp=fopen(in_file_name,"rb"); if(infp==NULL) { printf("待压缩文件 %s 打开失败\n",in_file_name); exit(1); } FILE *outfp=fopen(out_file_name,"wb"); if(outfp==NULL) { printf("压缩文件 %s 创建失败\n",out_file_name); exit(1); } for(int i=1;i<tree_size;i++)fwrite(&tree[i],sizeof(tree[i]),1,outfp); bit_cnt=0ULL; for(int i=0;i<MAX_BYTE;i++)bit_cnt+=(ULL)hehe[i]*(ULL)cnt[i+MAX_BYTE]; fwrite(&bit_cnt,sizeof(bit_cnt),1,outfp); int b=0; system("cls"); printf("生成文件总大小: %.3f KB\n",((double)bit_cnt+8.0*(double)sizeof(tree))/8192.0); printf("压缩率: %.3f%%\n",((double)bit_cnt+8.0*(double)sizeof(tree))/0.08/(double)filesize); printf("正在生成压缩文件... %3d.%02d%%",b/100,b%100); BYTE a; BYTE a1=0; int a2=0; for(int i=1;i<=filesize;i++) { fread(&a,sizeof(a),1,infp); for(int j=0;j<hehe[a];j++) { if(kkke[a][j])a1|=((BYTE)1<<a2); a2++; if(a2==8) { a2=0; fwrite(&a1,sizeof(a1),1,outfp); a1=0; } } if(b==(ULL)i*10000/filesize)continue; b=(ULL)i*10000/filesize; for(int k=0;k<7;k++)putchar('\b'); printf("%3d.%02d%%",b/100,b%100); } putchar('\n'); if(a2)fwrite(&a1,sizeof(a1),1,outfp); if(fclose(infp)) { printf("关闭输入文件 %s 失败\n",in_file_name); exit(1); } if(fclose(outfp)) { printf("关闭输出文件 %s 失败\n",out_file_name); exit(1); } } void dfs(int k,int b) { if(k>=MAX_BYTE) { k-=MAX_BYTE; for(int i=0;i<b;i++)kkke[k][i]=kkke1[i]; hehe[k]=b; } else { kkke1[b]=0; dfs(tree[k].son[0],b+1); kkke1[b]=1; dfs(tree[k].son[1],b+1); } } void build_tree() { system("cls"); printf("正在分析文件...\n"); priority_queue<int,vector<int>,cmp>q; for(int i=MAX_BYTE+MAX_BYTE-1;i>=MAX_BYTE;i--)q.push(i); for(int i=MAX_BYTE-1;i;i--) { tree[i].son[0]=q.top();q.pop(); tree[i].son[1]=q.top();q.pop(); cnt[i]=cnt[tree[i].son[0]]+cnt[tree[i].son[1]]; q.push(i); } } void read_data() { memset(cnt,0,sizeof(cnt)); FILE *infp=fopen(in_file_name,"rb"); if(infp==NULL) { printf("未找到待压缩文件\n"); exit(1); } fseek(infp,0,SEEK_END); filesize=ftell(infp); fseek(infp,0,SEEK_SET); BYTE a; int b=0; system("cls"); printf("文件总大小: %.3f KB\n",(double)filesize/1024.0); printf("正在读取文件... %3d.%02d%%",b/100,b%100); for(int i=1;i<=filesize;i++) { fread(&a,sizeof(a),1,infp); cnt[a+MAX_BYTE]++; if(b==(ULL)i*10000/filesize)continue; b=(ULL)i*10000/filesize; for(int k=0;k<7;k++)putchar('\b'); printf("%3d.%02d%%",b/100,b%100); } if(fclose(infp)) { printf("关闭输入文件失败\n"); exit(1); } }