菜鸟说:哈夫曼压缩的解压缩~~(附源代码)
解压就是压缩的逆过程……真是说起来容易做起来难啊……
不过最后还是做出来了,而且发现了前面的压缩函数的几个问题:
1.编码区不用存入补的零的个数:因为解压的时候是按照每个编码的长度截取的,所以到最后剩下的另不会造成任何影响,这样就不用再把补的零写进去了
2.从输入流读取数据的顺序要注意:比如下面是我昨天的代码
/************************ 再次读入文件信息,对应每一个字节写入编码 *********************/
// 再次读入文件信息,对应每一个字节写入编码
// 用来读取数据的文件输入流
FileInputStream ins = new FileInputStream(path1);
// 包装成缓冲流
BufferedInputStream bis = new BufferedInputStream(ins);
count = 0;
writes = "";
tranString = "";
int idata = bis.read(); //就是这行错了…************************
// 文件没有读完的时候
while ((bis.available() > 0) || (count >= 8)) {
// 如果缓冲区等待字符大于等于8
// System.out.println(count+"<<>>"+writes.length());
if (count >= 8) {
waiteString = "";// 清空要转化的码
for (int t = 0; t < 8; t++) {
waiteString = waiteString + writes.charAt(t);
}
// 删除前八位
writes = writes.substring(8);
count -= 8;// 写出一个8位的字节
int intw = changeString(waiteString);
bos.write(intw);// 写入到文件中
bos.flush();
} else {
// 读入idata字节 ,对应编码写出信息
count += SaveCode[idata].getN();
writes += SaveCode[idata].getNode();
// System.out.println(SaveCode[idata].getN()+"<<>>"+SaveCode[idata].getNode().length());
idata = bis.read();
}
}
count += SaveCode[idata].getN();
writes += SaveCode[idata].getNode();
// 把count 剩下的写入
int endsint = 0;
if (count > 0) {
waiteString = "";// 清空要转化的码
for (int t = 0; t < 8; t++) {
if (t < writes.length()) {
waiteString += writes.charAt(t);
} else {
waiteString += '0';
endsint++;
}
}
// System.out.println(waiteString.length());
bos.write(changeString(waiteString));// 写入最后补的0
bos.flush();
bos.write(endsint);// 写入最后补的0的个数
bos.flush();
System.out.println("压缩区写入了->" + endsint + "个0");
}
}
那个被我重点标出来的一行用该写在下面的else里面,不然会出现解压以后丢失最后一个字节的错误(修了半天才修好的……)
编程序的时候一定要理清思路啊……不然一点错了,就要重新检查……费时费力啊……
还有解压的时候,系统自带的 八十进制转化为二进制的函数Integer.toBinaryString(int i) 它转化成的01字符串如果是以0开头的话,会自动把0删掉,这样会造成我们的编码丢失,所以要修改一下,把它删除的0再补回来~~~
这样整个哈夫曼压缩和解压都完成了~下面这张图就是压缩的效果~哈~完工~(源文件有很多重复)
下面放出我的解压代码:
package 哈夫曼压缩;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
public class LoadFile {
private String path;
private String path1;
private Code ReadCode[] = new Code[256];
public LoadFile(String path, String path1) {
this.path = path;
this.path1 = path1;
}
public void realease() throws IOException {
FileInputStream fis = new FileInputStream(path);
BufferedInputStream bis = new BufferedInputStream(fis);
// 读取每个字节的编码长度
for (int i = 0; i < ReadCode.length; i++) {
Code a = new Code(bis.read(), null);
ReadCode[i] = a;
// if (ReadCode[i].getN() != 0)
// System.out.println("字节" + i + "的编码长度为:" + ReadCode[i].getN());
}
String writes = "";// 转化成01串的字符串
String waitString = "";
// writes+=changeInt(bis.read());
for (int i = 0; i < ReadCode.length; i++) {
while (writes.length() < ReadCode[i].getN()) {
writes += changeInt(bis.read());
}
waitString = "";
// 按照每个字节的编码长度读取字符串
for (int j = 0; j < ReadCode[i].getN(); j++) {
waitString += writes.charAt(j);
}
ReadCode[i].setNode(waitString);
waitString = "";
// 移除已经写入的数据
writes = writes.substring(ReadCode[i].getN());
}
// 创建映射
HashMap<String, Integer> map = Setmap(ReadCode);
/************ 读取文件信息,转换成原来的数据写入文件 *****************/
writes = "";
waitString = "";
// 创建文件输出流
FileOutputStream fos = new FileOutputStream(path1);
BufferedOutputStream bos = new BufferedOutputStream(fos);
while (bis.available() > 2) {
writes = writes + changeInt(bis.read());// 先读取一串01串
// System.out.println("待检查的字符串为:" + writes);
for (int i = 0; i < writes.length(); i++) {
waitString += writes.charAt(i);
if (map.containsKey(waitString) == true) {
bos.write(map.get(waitString));
bos.flush();
// System.out.println("写入了" + waitString + "<>字节"
// + (char) (int) map.get(waitString));
// System.out.println("编码长度为" + waitString.length());
writes = writes.substring(waitString.length());
// System.out.println("剩下的字符串为:" + writes);
waitString = "";
i = -1;
}
}
waitString = "";
}
System.out.println("还剩下:" + bis.available());
String last = changeInt(bis.read());
int ls = bis.read();
System.out.println("补了" + ls + "个0");
// 去除最后几个0
String temp;
temp = last;
last = "";
for (int i = 0; i < 8 - ls; i++) {
last += temp.charAt(i);
}
writes += last;
System.out.println("待检查的字符串为:" + writes);
for (int i = 0; i < writes.length(); i++) {
waitString += writes.charAt(i);
if (map.containsKey(waitString) == true) {
bos.write(map.get(waitString));
bos.flush();
System.out.println("写入了" + waitString + "<>字节"
+ (char) (int) map.get(waitString));
// System.out.println("编码长度为" + waitString.length());
writes = writes.substring(waitString.length());
System.out.println("剩下的字符串为:" + writes);
waitString = "";
i = -1;
}
}
}
// 创建映射
public HashMap<String, Integer> Setmap(Code[] a) {
HashMap<String, Integer> map = new HashMap<String, Integer>();
for (int i = 0; i < a.length; i++) {
map.put(a[i].getNode(), i);
}
return map;
}
/**
* 将一个整数转化为八位字符串
*
* @param s
* @return
*/
public String changeInt(int i) {
String s = Integer.toBinaryString(i);
if (s.length() < 8) {
int bu = 8 - s.length();
String temp = s;
s = "";
for (int i1 = 0; i1 < bu; i1++) {
s += '0';
}
s += temp;
}
// System.out.println("读出的字符串为:\t" + s);
return s;
}
}