这几天完成了哈夫曼原理压缩文件的实现.. 虽然这个实现压缩的速度相当让人蛋疼.. 不过这也算是加深了对压缩原理的的理解吧. 话说. 我还用系统给的类写了个Zip格式的压缩.. 比较之下才发现自己写的那些代码实在是不及他人的皮毛啊. 同样是一个类. 我的效率比起系统的来说...... 这根本就是没法比啊. 前路漫漫. 自己要学的,要改的还有很多啊.. 先谈谈自己的这个上不了眼压缩.. 首先是统计各个字节出现的次序
// 创建映射集,每个字节对应其出现的次数.
HashMap<Byte, Integer> map = new HashMap<Byte, Integer>();
try {// 文件地址正确的时候创建文件输入流
FileInputStream fis = new FileInputStream(path);
// 封装成缓冲流
BufferedInputStream bis = new BufferedInputStream(fis);
int len = bis.available();
// 每次读取一个字节
byte data;
file = new byte[len];
int i = 0;
while (len > 0) {
data = (byte) bis.read();
// System.out.println(data);
file[i] = data;
// 如果字节在映射中不存在,则放入1
if (map.get(data) == null) {
map.put(data, 1);
} else {// 如果字节在映射中已经存在,则value值在原来基础上加1
map.put(data, map.get(data) + 1);
}
i++;
len = bis.available();
}
fis.close();
} catch (Exception ef) {
ef.printStackTrace();
}
然后再根据各字节出现过的次数大小(即各个字节出现的频率)来构造哈夫曼树,并通过这棵哈夫曼树来为每个字节编码,于是每个字节都有一个唯一的哈夫曼编码与之对应.然后再通过文件中各个字节的顺序来得到整个文件的所有字节的哈夫曼编码,再将这些编码分割成8位8位的.. 然后就能将这些字符串变成字符串写到文件中去了.
// 创建文件输出流
FileOutputStream fos = new FileOutputStream(des);
// 包装成基本类型数据流将字节长度写入文件
DataOutputStream dos = new DataOutputStream(fos);
// String转化成的字节数组的长度
dos.writeInt(str.length() / 8 + 1);
byte[] by;
// 字符串的长度
int slen = str.length();
if (slen % 8 == 0) {// 如果字符串长度正好是8的整数倍,即说明最后没有补0,byte数组的最后一个数放0,表示没有补0
dos.writeInt(1);// 字符串大小正好是8的整数倍
by = new byte[slen / 8 + 1];
String s;
int c = 0;
// 循环,每次得到一个8位的01串
while (str.length() >= 8) {
// 得到8位01串
s = str.substring(0, 8);
BigInteger bi = new BigInteger(s, 2);// 将01串转换为BigInteger类型
String s1 = bi.toString(10);// 转换为10进制结果
int i = Integer.valueOf(s1);
by[c] = (byte) i;
strlist1.put(by[c], s);
// 将得到的8位01串丢掉.
str = str.substring(8);
c++;
}
by[c] = 0;
dos.write(by);
} else {// 如果字符串长度不是8的整数倍,则说明要多留出一位来存放那个不满8zz位的"字节",同时还要多一位来存放补上的0的个数.
dos.writeInt(0);// 字符串的长度不是8的整数倍
by = new byte[slen / 8 + 2];
String s;
int c = 0;
// 循环,每次得到一个8位的01串
while (str.length() > 8) {
// 得到8位01串
s = str.substring(0, 8);
BigInteger bi = new BigInteger(s, 2);// 将01串转换为BigInteger类型
String s1 = bi.toString(10);// 转换为10进制结果
int i = Integer.valueOf(s1);
by[c] = (byte) i;
strlist1.put(by[c], s);
// 将得到的8位01串丢掉.
str = str.substring(8);
c++;
}
// 往字符串后面补0.
int sl = str.length();
for (int k = 0; k < 8 - sl; k++) {
str += 0;
}
BigInteger bi = new BigInteger(str, 2);// 将01串转换为BigInteger类型
String str1 = bi.toString(10);// 转换为10进制结果
int i = Integer.valueOf(str1); // 将字符串转成int类型
by[c] = (byte) i; // 强制转型成byte类型.放入数组,写到文件中.
strlist1.put(by[c], str);
by[c + 1] = (byte) (8 - sl);
dos.write(by);
}
// 包装成对象输入流将码表直接以对象的形式写入文件
ObjectOutputStream oos;
oos = new ObjectOutputStream(fos);
oos.writeObject(writemap);
oos.writeObject(strlist1);
oos.flush();
// 强制输出
dos.flush();
fos.close();
由于上次在实现自定义画板的文件保存时,用了对象数据流, 尝到了甜头.. 于是我这次的码表就直接用对流输出流来写.. 这个方法虽然省事.. 但是会产生"副作用":会降低压缩比率.. 貌似对读写的时间也有影响..
接下来就是解压了.. 其实就是压缩的逆过程吧,, 只要好好注意.. 自己是怎么样把各个字节写入的,再一步一步将其还原回来就是了.
// 得到文件地址
FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(des);
// 包装成数据流
DataInputStream dis = new DataInputStream(fis);
DataOutputStream dos = new DataOutputStream(fos);
int arraylen;
// 读取字节数组的长度
arraylen = dis.readInt();
int flag = dis.readInt();// 此处a为标志,1表示被压缩的源文件的哈夫曼编码总长度是8的整数倍
// 0表示被压缩的源文件的哈夫曼编码的总长度不是8的整数倍
// 被压缩文件的源文件的哈夫曼编码长度是8的整数倍,即只多了一位放0.(arraylen==slen%8+1)
if (flag == 1) {
by = new byte[arraylen - 1];// 最后一位直接丢弃
dis.read(by);
dis.read();
ObjectInputStream ois = new ObjectInputStream(fis);
maps = (HashMap) ois.readObject();
m = (HashMap) ois.readObject();
// 将字节数组转成字符串
String s1 = "";
for (int k = 0; k < by.length; k++) {
s1 += m.get(by[k]);
}
String s2;
int s2l = 0;
int sl = 1;
int s1l = s1.length();
while (s1l > 0) {
// 首先从一位开始找匹配,找到就写文件
s2 = s1.substring(s2l, sl);
while (maps.get(s2) == null) {
sl++;
s2 = s1.substring(s2l, sl);
}
dos.write(maps.get(s2));
s1 = s1.substring(sl);
s2l = 0;
sl = 1;
s1l = s1.length();
}
} else {// 不是8的整数倍..(arraylen==slen%8+1)
by = new byte[arraylen];
dis.read(by);
byte num = dis.readByte();// 读出最后一个记录补0个数的字节
ObjectInputStream ois = new ObjectInputStream(fis);
maps = (HashMap) ois.readObject();
m = (HashMap) ois.readObject();
String s = "";
for (int k = 0; k < by.length; k++) {
s += m.get(by[k]);
}
int initlen = s.length();
s = s.substring(0, initlen - (int) num);// 截取第一位到补0的第一位.
String s2;
int s2l = 0;
int sl = 1;
int s1l = s.length();
while (s1l > 0) {
// 首先从一位开始找匹配,找到就写文件
s2 = s.substring(s2l, sl);
while (maps.get(s2) == null) {
sl++;
s2 = s.substring(s2l, sl);
}
dos.write(maps.get(s2));
s = s.substring(sl);
s2l = 0;
sl = 1;
s1l = s.length();
}
}
dos.flush();
fos.close();
鉴于压缩一个大文件实在是太慢了.. 就选了一个比较小的文件来示例了.. 压缩的比率也的确不高啊....
然后就是利用系统提供的一个类.写了个压缩成zip格式的文件. 压缩完了之后直能用zip格式解压器就能打开.像winRAR就能直接打开查看.. 用了这个类... 代码量少了不止是一行两行,, 压缩的速度.. 压缩的比率... 唉 , 看得人纠结啊.. 学无止境呀,还有很多东西需要好好努力去学..
不过这个方法暂时还有点小问题没解决.. 中文名字乱码!! 这是java使用的是unicode编码.. 而winRAR却不是.. 所以才导致了这个问题.. 这个问题还真让我有点蛋疼,, 实在不行的话就自己写个类来解压吧..呵呵..
具体实现暂时还只写了个压缩的方法. 并且只给了固定的地址的压缩.
- 大小: 13.2 KB
- 大小: 10.3 KB
分享到:
相关推荐
mypage文件可能包含了实现哈夫曼压缩和解压缩算法的C源代码文件,以及相关的测试数据或结果。通过阅读和理解这些代码,你可以深入学习哈夫曼编码的工作原理,以及如何在C语言中实现这一算法。同时,还可以了解到如何...
总之,哈夫曼压缩解压缩是数据压缩领域的一个重要方法,通过MFC和VC++,我们可以构建出直观且高效的压缩工具,便于学习和研究。在这个过程中,理解哈夫曼编码的原理、掌握MFC的使用以及实现压缩和解压缩的算法,都是...
《哈夫曼压缩》是一种广泛应用于数据压缩领域的高效算法,由大卫·艾尔·哈夫曼在1952年提出。它属于一种基于字符频率的无损压缩方法,特别适用于压缩那些存在大量重复字符的数据。哈夫曼编码是哈夫曼压缩的核心,...
在Java中实现哈夫曼压缩涉及到的主要步骤包括统计字节频率、构建哈夫曼树以及生成哈夫曼编码。首先,我们需要创建一个字节类(`NodeData`)来表示每个字节及其对应的权重(频率)。下面我们将详细讲解这些步骤: 1....
在Java中实现哈夫曼压缩和解压涉及到以下几个关键知识点: 1. **哈夫曼树**: 哈夫曼树(Huffman Tree)是一种带权路径长度最短的二叉树,也称为最优二叉树。它通过将频率较低的字符编码为较短的位序列,而频率较...
vc++哈夫曼压缩算法 vc++哈夫曼压缩算法
哈夫曼压缩是一种高效的数据压缩方法,它基于字符出现频率构建一种特殊的二叉树——哈夫曼树。在计算机科学中,尤其是信息处理和文件压缩领域,哈夫曼编码是广泛应用的技术之一。ASC II码是计算机中用8位二进制数...
在Java编程环境中实现哈夫曼压缩与解压缩程序,我们可以利用面向对象的特性,设计多个类来完成不同部分的功能。 1. **FileChooserDemo.java**:这是一个用户界面类,通常包含用于让用户选择输入和输出文件的控件。...
在C++中实现哈夫曼压缩和解压,主要涉及到数据结构(如优先队列、二叉树)和文件操作(读写)。`huffmain`可能是这个C++项目的主程序文件,其中可能包含了构建哈夫曼树、生成编码、压缩和解压等核心功能的实现。具体...
哈夫曼压缩与解压缩源码.zip哈夫曼压缩与解压缩源码.zip哈夫曼压缩与解压缩源码.zip哈夫曼压缩与解压缩源码.zip哈夫曼压缩与解压缩源码.zip哈夫曼压缩与解压缩源码.zip哈夫曼压缩与解压缩源码.zip哈夫曼压缩与解压缩...
在C++中实现哈夫曼压缩软件,我们需要理解以下几个核心概念和技术: 1. **哈夫曼树**:哈夫曼树是一种带权路径长度最短的二叉树,也称为最优二叉树。构建哈夫曼树的过程是通过合并频度最低的两个节点来逐渐构建整个...
本压缩包文件包含了一个可以直接运行的哈夫曼压缩与解压程序,是用C++语言编写的。C++是一种通用的、面向对象的编程语言,具有高效、灵活和丰富的库支持,非常适合实现这样的算法。 在压缩过程中,首先需要统计输入...
在Java中实现哈夫曼压缩涉及到以下几个关键步骤: 1. **统计字符频率**:首先,需要遍历输入文本,统计每个字符出现的次数,生成一个字符频率表。这是构建哈夫曼树的基础。 2. **构建哈夫曼树**:使用字符频率表,...
哈夫曼编码是一种高效的数据压缩方法,由大卫·哈夫曼在1952年提出。它是基于一种称为哈夫曼树(也叫最优二叉树)的数据结构。在这个课程设计中,你将深入理解哈夫曼编码的原理,并通过C++编程语言实现文件的压缩与...
哈夫曼压缩算法,全称为哈夫曼编码(Huffman Coding),是一种高效的无损数据压缩方法,由美国科学家大卫·艾尔·哈夫曼在1952年提出。它是基于字符频率(权重)构建最优二叉树的思想,通过创建一棵特殊的二叉树——...
在Java中实现哈夫曼压缩通常包括以下几个关键步骤: 1. **构建哈夫曼树**:首先,需要统计输入文本中每个字符出现的频率。然后,根据这些频率创建一个哈夫曼树。哈夫曼树是一种特殊的二叉树,其特点是叶子节点代表...
哈夫曼压缩是一种高效的数据编码方法,主要用于无损数据压缩,其原理是基于字符出现频率构建最优的二叉树(哈夫曼树),并以此进行编码。在C++实现哈夫曼压缩的过程中,我们需要理解以下几个关键知识点: 1. **...
在C++中实现哈夫曼压缩,我们需要理解以下几个关键知识点: 1. **哈夫曼树(Huffman Tree)**:哈夫曼树是一种特殊的二叉树,也称为最优二叉树,其叶子节点代表待编码的字符,非叶子节点表示字符的组合。树的构建...
哈弗曼编码(Huffman Coding)是一种数据压缩算法,由美国计算机科学家大卫·艾尔文·哈弗曼在1952年提出。这个算法基于一种称为“最优二叉树”(也称哈弗曼树)的数据结构,主要用于对频率不同的字符进行编码,从而...