基于Huffman树的文件压缩原理及C语言实现(二)

在上文基于Huffman树的文件压缩原理及C语言实现(一)中已经介绍并实现了如何建立Huffman树,得到Huffman编码,这篇我们将会接着说。如何通过Huffman树,实现文件压缩。

实现思路

任何文件都可以看作是由字节组成的字节块,将字节看作基本编码单元,一个文件就可以看作是由字节组成的信息串。对文件中各字节的出现频率进行统计,并以出现频率作为每个字节块的权值,就可以用字节为叶结点构造哈夫曼树,进而构造出各字节的对应哈夫曼编码。
对于源文件的字节编码是一种8位定长编码,而将各字节用哈夫曼编码进行重新编码,就有可能使得总的编码长度更短,这样将编码看做二进制位,每个8位作为一个字节写入压缩文件中,根据构建哈弗曼树的算法,在源文件中出现频率高的字符所对应的编码长度小,所以总的文件长度会小于原来的文件长度,从而达到文件压缩的效果。
对于每一个字节块,都是8位的,所以可以用ASCII码值对应每一个字符,也就是一个0~~255的数,可以创建一个256长度的数组,来记录每一个ASCII码值出现的频率。所以需要先将要压缩的文件遍历一遍,统计一下每一个字符出现的频率,然后调用求Huffman树的函数,建立一棵对应此文件字符出现的频率的Huffman树,并且求出对应每一个ASCII码的Huffamn编码。然后再遍历一遍,每次读出一个字节,根据其ASCII码值找出对应的Huffman编码,如果Huffman编码长度不足8位时,就再从文件中读出下一个字符,并且得到他的Huffman编码,与之前的没有写入文件的编码作为一个整体;如果此时的编码长度大于或等于8了,就将它对应的ASCII码值写入压缩文件中。就这样边读源文件,边进行翻译写入压缩文件,直到读完源文件。这样就完成了文件的压缩功能,由于还学要正确的解压文件,所以在进行压缩的时候还应该把Huffman树一块保存起来,所以压缩文件的前面一部分就是压缩文件是建立的Huffman树,而压缩文件的开头四个字节用来记录文件的扩展名。
当进行解压的时候,根据压缩文件的格式,先读出源文件的扩展名,然后读出Huffman树,根据Huffman树进行解压。解压时,同样可以一边解压一边写入解压后的文件中,即每读出一个字节,就根据他的ASCII码值,查找Huffman树对应的叶子节点,叶子节点的下标就是源文件对应的ASCII码值,然后将得到的ASCII码值写入压缩后的文件中,就这样直到读完解压文件,就完成了文件的解压工作。

实现代码

版本一

Huffman树的实现已经在(一)中实现。剩下的代码如下:

#include "HuffmanTree.h"
#define NAMESIZE 500

void zip(const char*s)
{
	// 实现压缩功能
	// s:为要压缩的地址和文件名。 
	FILE*pr,*pw;	
	int a,i=0 ,w[256],j,n=256,m=2*n-1;
	HuffmanCode HC,hc;HuffmanTree HT;
	char zipname[NAMESIZE]="zip",c=' ';//压缩后的压缩文件名为zip+原文件名+.txt. 
	while(s[i]!='.'){zipname[3+i]=s[i];i++;}
	zipname[3+i]='.';zipname[4+i]='t';zipname[5+i]='x';zipname[6+i]='t';zipname[7+i]='\0';

	pr=fopen(s,"rb");

	if(!pr){
		printf("文件打开失败!");exit(1);
	}
	for(int i=0;i<256;i++)w[i]=0;
	a=fgetc(pr);
	while(!feof(pr))
	{
		w[a]++;a=fgetc(pr);
	}
	fclose(pr);

	HuffmanCoding(HT,HC,w,256);//求出霍夫曼书,下面将文件的扩展名和霍夫曼树存入压缩文件中;
	 
	pw=fopen(zipname,"wb");

	//先写入扩展名 ,扩展名占 4 个字节。 不足4个用空格' '补齐; 
	j=0;
	while(s[++i]){
		fwrite(s+i,1,1,pw);j++;
	}
	while(j++<4)fwrite(&c,1,1,pw);
	//下面是写入霍夫曼树。 
	for(int i=n+1;i<=m;i++) {
		fwrite(&((HT+i)->lchild),2,1,pw);
		fwrite(&((HT+i)->rchild),2,1,pw);
	}
	
	//此时霍夫曼树已经存入压缩文件中。 
	pr=fopen(s,"rb");//重新打开文件遍历文件进压缩。 
	a=fgetc(pr);
	i=0;int b=0;hc=HC;char*p=*(hc+a+1);
	while(!feof(pr)||*p!='\0')
	{
		for(i=0;i<8;i++){
			if(*p=='\0'){
				a=fgetc(pr);
				if(a>=0)p=hc[a+1];
				else {
						int h=1;
						for(int j=0;j<8-i;j++)h=h*2;
						b=b*h;break;
					}
			}
			int h=1;
			for(int j=0;j<7-i;j++)h=h*2;
			b=b+(*p-48)*h;
			++p;
		}
		fwrite(&b,1,1,pw);b=0;
	}
	printf("压缩成功!\n");
	
	fclose(pr);fclose(pw);
}

void rezip(const char*s)
{
	// 实现解压功能
	// S:为压缩文件的地址和文件名。
	printf("进行文件解压\n");
	FILE*pr,*pw;	
	int a,i=0,j,n=256,m=2*n-1;UInt32 w[256];
	HuffmanCode HC,hc;HuffmanTree HT;
	char rezipname[NAMESIZE]="re";
	i=0;
	while(s[i]!='.'){rezipname[2+i]=s[i];i++;}
	rezipname[2+i]='.';i++;
	
	pr=fopen(s,"rb");
	if(!pr){
		printf("文件打开失败!");exit(1);
	}
	j=0;a=fgetc(pr);
	while(j<4){
		rezipname[2+i]=a;if(j<3)a=fgetc(pr);j++;i++;
	}
	HT=(HuffmanTree)malloc(sizeof(HTNode)*(m+1));
	HT[0].weight=0;HT[0].parent=0;HT[0].lchild=0;HT[0].rchild=0;
	for(i=1;i<=n;i++){
		HT[i].weight=0;//此时不需要权重,所以可以随便赋值。 
		HT[i].lchild=0;
		HT[i].rchild=0;
	}
	
	for(i=n+1;i<=m;i++)
	{
		HT[i].weight=0;//此时不需要权重,所以可以随便赋值。 
		fread(&a,2,1,pr);HT[i].lchild=a;HT[a].parent=i;
		fread(&a,2,1,pr);HT[i].rchild=a;HT[a].parent=i;
	}
	HT[m].parent=0;
	//此时HT为霍夫曼树。

	// 下面重新读取原文件根据Huffman树得到对应的Huffman编码,写入压缩后的文件。
	int gm=0;
	char aa[80000],b[8];int x[10000],d;a=fgetc(pr);
	while(!feof(pr))
	{
			for(int i=0;i<8;i++){
				if(a){
					b[7-i]=48+a%2;
					a=a/2;
				}
				else b[7-i]='0';
			}
			for(int i=0;i<8;i++){
				aa[8*j+i]=b[i];
			}
			j++;
			d=a;
			a=fgetc(pr);
	}
	for(i=0;i<8;i++){
		if(a){
			b[7-i]=48+a%2;
			a=a/2;
		}
		else break;
	}
	for(int k=0;k

运行结果

基于Huffman树的文件压缩原理及C语言实现(二)_第1张图片
如上图,运行程序会将mystring.txt压缩成zipmystring.txt,然后将zipmystring.txt解压成rezipmystring.txt。
缺点:
1、压缩文件名称是写死在代码中的。
2、解压缩是将整个文件全部解压后才往文件中写的,所以太大的文件就会越界。

版本二

显然版本一只是实现了指定文件的压缩,还存在很大问题。为了解决大文件解压的问题,我改成了边解压边写文件的方法。代码可以到此处下载:下载版本二源码

运行结果

基于Huffman树的文件压缩原理及C语言实现(二)_第2张图片

版本三

为了实现文件名称动态获取的方式,我将文件名称在调用main函数的时候传进来,并且通过添加注册表,将此压缩和解压缩程序添加了文件的右键菜单。同时给压缩后的文件关联了图标。代码可以到此处下载:下载版本三源码

运行结果

基于Huffman树的文件压缩原理及C语言实现(二)_第3张图片

你可能感兴趣的:(数据结构)