菜鸟说:哈夫曼压缩的解压缩~~(附源代码)

解压就是压缩的逆过程……真是说起来容易做起来难啊……

 

不过最后还是做出来了,而且发现了前面的压缩函数的几个问题:

 

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;
	}
}
 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值