初学者说:哈夫曼压缩的解压缩~(附源代码)
菜鸟说:哈夫曼压缩的解压缩~~(附源代码)
解压就是压缩的逆过程……真是说起来容易做起来难啊……
不过最后还是做出来了,而且发现了前面的压缩函数的几个问题:
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; } }