多媒体大作业

2020-03-03 12:01:06 来源:范文大全收藏下载本文

多媒体大作业 文件压缩与解压缩的实现

学号: 姓名: 班级:

2015/12/17

日期:

目录

一 文件

二 压缩解压缩实现细节

三 代码

四 测试结果

五 存在问题

一文件

文件格式 :.txt .jpg 文件都可以

本次测试 为一篇文章的txt文件,以及一张图片。

二压缩解压缩实现细节

算法:哈夫曼算法 原理及步骤:

1.读取文件,统计每一种字节出现的次数,将出现的字节种类与对应的次数保存起来(可采用数组或者是HashMap,或者是其他的数据结构)

保存完了之后干什么呢??当然是构建哈弗曼树呀。第二步:

2.利用得到的字节与对应的频次构建哈弗曼树,需要注意的是,构建树的时候是以字节出现的频次作为我们的评判标准,出现次数越多的放在越上层。

比如我们上面所说的这个文件,它所构成的树应该是这样的:

我们现在得到的树还处于未编码的状态,那么第三步毫无疑问就是我们所说的编码了:

3.将得到的哈弗曼树进行编码

编码之后的树就变成这个样子了(采取向左编1的方式):

编码之后,A所对应的的编码就是111,B就是110,C是10,D是0,那么我们的文件就变成了11111011,01010100,000,下面要把这些10串每8个作为一组编码成一个新的字节(2进制转10进制),所以这里每8位我也特别用逗号表示出来了。

(1)如果最后几位不满8个怎么办?

定义这样一个规则,在最后的位置补0,在文件的末尾再加一位表示最后一个数补0的个数,这样的话这个问题就变得很简单了。

(2)压缩之后怎么知道压缩前每种字节对应的编码是什么样子的?

那么要完成压缩,最关键的一步,还要将压缩时所得到的每个字节对应的码表写入文件,这样才能保证,所做的工作是可逆的。 4.根据每种字节对应的哈弗曼编码,将文件转换成01字符串 5.将得到的01串重新编码成新的byte数组写入文件

6.对象化的实现方法中,提供了按位输入与输出的类,这些类都是自定义的,因为在编程中所能操作的计算机的最小单元是byte,那么在这个类中是怎么做的呢?将一个字节进行8次移位按位与运算,就得到了这个字节的8个bit的表示方式。

三代码

哈夫曼树类

package 哈弗曼压缩;

import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.PriorityQueue;

public cla HuffmanTree {

private CharCounter theCounts;//字符统计类对象

private HuffNode root;//根结点

private HuffNode[] theNodes=new HuffNode[BitUtils.DIFF_BYTES+1];//public static final int ERROR=-3;//错误

public static final int INCOMPLETE_CODE=-2;//不完全的结点编码 public static final int END=BitUtils.DIFF_BYTES;//字节的溢出位 /** * 实例化一个字符统计类对象 */ public HuffmanTree(){

} /** * 可以通过CharCounter对象来创建一个huffmanTree对象 * @param cc CharCounter对象 */ public HuffmanTree(CharCounter cc){ theCounts=cc; root=null; theCounts=new CharCounter(); root=null; 存储HuffNode的数组

createTree();//创建HuffmanTree } /** * 得到要寻找的字符编码所在的树结点,如果该字符不在树上,则返回null表示出错,否 * @param ch 当前结点的下标 * @return 结点相对的字符编码数组 */ public int[] getCode(int ch){

HuffNode current=theNodes[ch];

if(current==null) return null; String v=\"\";//结点的编码

HuffNode parent=current.parent;

while(parent!=null){

if(parent.left==current) v=\"0\"+v;//左结点编码 else 则,通过父亲链逆向查找,直到到达根结点

}

} v=\"1\"+v;//右结点编码

//向下遍历

current=current.parent; parent=current.parent; int len=v.length(); int [] result=new int[len];//创建一个与编码相同大小数组 for(int i=0;i

* @return 存储在结点中的值(如果结点不是叶子结点,则返回符号INCOMPLETE) */ public int getChar(String code){

} /** * 写入编码表的方法

* @param out 写入的数据流 * @throws IOException */ public

void

writeEncodingTable(DataOutputStream

out)

throws HuffNode leaf=root;//获取根结点 int len=code.length(); //按照编码向左或向右遍历到叶子结点

for(int i=0;leaf!=null&&i

if(code.charAt(i)==\'0\') leaf=leaf.left; leaf=leaf.right; else //根结点为空

if(leaf==null) return ERROR; return leaf.value; IOException{ for(int i=0;i

if(theCounts.getCount(i)>0){ out.writeByte(i);//将字节写入(通常是文件)

out.writeInt(theCounts.getCount(i));//将字节出现的次数写入(通常是文件)

} }

} //最后写入0表示编码的结束 out.writeByte(0); out.writeInt(0); /** * 读取编码表的方法

* @param in 数据输入流对象 * @throws IOException */ public

void

readEncodingTable(DataInputStream

in)

throws IOException{ for(int i=0;i

} ch=in.readByte();//读到的字节 num=in.readInt();//字符出现的次数 if(num==0)//如果读到0表示编码表的结束

break; theCounts.setCount(ch, num); createTree();//创建HuffmanTree } /** * 构造哈弗曼编码树的方法 */ public void createTree(){

//创建一个优先队列来保存HuffNode PriorityQueue pq=new PriorityQueue();

for(int i=0;i

}

theNodes[END] =new HuffNode(END,1,null,null,null); pq.add(theNodes[END]); //当剩余的结点多于一个时 while(pq.size()>1){ if(theCounts.getCount(i)>0){//如果某一个字节出现过

HuffNode newNode=new theNodes[i]=newNode; HuffNode(i,theCounts.getCount(i),null,null,null); pq.add(newNode);//将新结点添加到队列中 } //每次取出当前最小的两个结点

HuffNode n1=pq.remove();//remove方法与poll方法的唯一不同之处在于:此队列为空时将抛出一个异常

HuffNode n2=pq.remove();

} 解压缩类

package 哈弗曼压缩; /** * 包含解压缩的包装类 */ import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream;

public cla HZIPInputStream extends InputStream{

private BitInputStream bin;//位输入流

private HuffmanTree codeTree;//编码的HuffmanTree对象 /** * 封装InputStream对象,实例化HuffmanTree对象与BitInputStream对象,并读

} //将最小的两个结点链接形成新结点 HuffNode n1.parent=n2.parent=result; //将新结点添加到队列当中 pq.add(result);

result=new HuffNode(INCOMPLETE_CODE,n1.weight+n2.weight,n1,n2,null); root=pq.element();//根结点就是队列中的最后一个结点 } 入哈弗曼编码

* @param in

* @throws IOException */ public HZIPInputStream(InputStream in) throws IOException{

} /** * 读取文件的方法 */ //数据输入流

DataInputStream din=new DataInputStream(in);

codeTree=new HuffmanTree(); codeTree.readEncodingTable(din);

bin=new BitInputStream(in);

} public int read() throws IOException{

} /** * 关闭输入流 */ public void close() throws IOException{ } bin.close(); String bits=\"\";//哈弗曼编码的字符串 int bit;//位

int decode;//解码后的字符 while(true){

} bit=bin.readBit(); if(bit == -1) throw new IOException(\"Unexpected EOF\");//意外的资源结束

bits+=bit; decode=codeTree.getChar(bits);//获取编码对应的字符

if(decode==HuffmanTree.INCOMPLETE_CODE)//向下搜索到叶子结点

continue; else if(decode==HuffmanTree.ERROR)//编码出错

throw new IOException(\"Unexpected error\"); else if(decode==HuffmanTree.END)//编码溢出

return -1; else return decode; 压缩类

package 哈弗曼压缩; /** * 包含压缩的包装类 */ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream;

public cla HZIPOutputStream extends OutputStream{

private

ByteArrayOutputStream

byteOut=new ByteArrayOutputStream();//实例化的一个字节数组输出流对象

private DataOutputStream dout;//数据输出流对象 /**

* 实例化一个DataOutputStream对象的构造方法 * @param out 输出流对象 * @throws IOException */ public HZIPOutputStream(OutputStream out) throws IOException{ } /** * 写入编码频率的方法 */ public void write(int ch) throws IOException{ } /** * 关闭流的方法 */ public void close() throws IOException{ byte[] theInput=byteOut.toByteArray();//将字节数组输出流转换数据转

byteIn=new byteOut.write(ch); dout=new DataOutputStream(out); 换成字节数组进行输入

ByteArrayInputStream ByteArrayInputStream(theInput);//将字节数组封装到字节输入流中

CharCounter countObj=new CharCounter(byteIn);//实例化字符统计对象byteIn.close();//关闭字节输入流

HuffmanTree

codeTree=new

HuffmanTree(countObj);//

过并统计字节数组的字符出现的次数

CharCounter对象实例化一个HuffmanTree对象

codeTree.writeEncodingTable(dout);//将编码写入数据输出流中

BitOutputStream bout=new BitOutputStream(dout);//创建位输出流

//将按编码转换后的位写入

int len=theInput.length; for(int i=0;i

//关闭流

bout.close(); byteOut.close(); 符

}

}

四测试结果

文件压缩前

Txt文件

界面

开始压缩txt

Txt压缩完

txt解压缩

Txt解压缩完

经过压缩及解压缩后的文件重新打开

Jpg压缩及解压缩完后。

五存在问题

当文件较小或过大时,压缩之后的文件比源文件还大。 文件较小时,由于要写入编码表,所以造成了较大的空间占用。

而文件较大时,由于各种字节出现的频率已经趋于了相近的地步,那么我们再来回顾一下哈弗曼的压缩过程时会发现,极端情况下,当所有字节都出现过,且出现的次数相同时,每一种字节的编码长度都达到了8位(哈弗曼树的第9层刚好有256个叶子结点),达不到压缩的效果。

多媒体作业心得体会

多媒体技术及应用课程大作业(推荐)

大作业

大作业

多媒体课件制作作业

多媒体教学软件开发作业

仓储大作业

大作业布置

acce大作业

DSP大作业

《多媒体大作业.doc》
多媒体大作业
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档
下载全文