将压缩和解压放在了一个程序里面,并加入了进度显示功能。
并不完善,因为使用'\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);
}
}