哈夫曼树完成文件的压缩和解压

1、在这里只有工具类,依赖的树节点和树的类,见另一篇博客(https://blog.csdn.net/riapgypm/article/details/106103996)里的定义

2、压缩工作类的实现如下:

package com.cn.test.tree.zip;


import java.io.*;
import java.util.*;

/**
 * 压缩工具类
 */
public class ZipFileUtil {

    public static Map<Integer,String> huffCodes = new HashMap<>();
    public static Map<String,Integer> reverseHuffCodes = new HashMap<>();


    private static byte[] readFile(String filePath){
        byte[] content = null;
        try {
            FileInputStream fileReader = new FileInputStream(new File(filePath));
            content = new byte[fileReader.available()];
            fileReader.read(content);
            fileReader.close();
            return content;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return content;
    }

    private static void writeToZipFile(byte[] bytes,String target){
        try {
            FileOutputStream fos = new FileOutputStream(new File(target));
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(bytes);
            oos.writeObject(huffCodes);
            oos.close();
            fos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private static void unZipWriteToFile(byte[] bytes,String target){
        try {
            FileOutputStream fos = new FileOutputStream(new File(target));
            fos.write(bytes);
            fos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private static byte[] readZipFile(String filePath){
        byte[] content = null;
        try {
            FileInputStream fileReader = new FileInputStream(new File(filePath));
            ObjectInputStream ois = new ObjectInputStream(fileReader);
            byte[] zipContent = (byte[])ois.readObject();
            huffCodes = (Map<Integer,String>)ois.readObject();
            ois.close();
            fileReader.close();
            return zipContent;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return content;
    }

    /**
     * 普通文件压缩
     * @param sourcePath
     * @return
     */
    public static  void zipFile(String sourcePath,String targetPath){
        if(sourcePath==null){
            return;
        }
        System.out.println("原始文件路径:"+sourcePath);
        //构建哈夫曼树列表
        byte[] bytes = readFile(sourcePath);
        System.out.println("原始字节长度:"+ Arrays.toString(bytes));

        //构建哈夫曼村
        HuffTree huffTree = new HuffTree();
        huffTree.buildTree(bytes);

        huffTree.obtainHuffCodes(huffTree.getRoot(),"",huffCodes);
        //生成压缩后的字符串二进制数
        StringBuilder binaryBuilder = new StringBuilder();
        for (byte b:bytes){
            binaryBuilder.append(huffCodes.get((int)b));
        }
        String strBinary= binaryBuilder.toString();
        System.out.println("字符串二进制数:"+strBinary);
        //把字符二进制数转换成真实的二进制数
        int len = (strBinary.length()+7)/8;
        byte[] result = new byte[len+1];
        //byte[0]留出来,如果结尾补了位,把补位的数字放在这里
        int index = 1;
        for (int i = 0 ;i <strBinary.length();){
            if(i+8>=strBinary.length()){
                String last = strBinary.substring(i);
                //补位,使其正好是8位
                last += "00000000".substring(8-(i+8-strBinary.length()));
                result[index++] = (byte)Integer.parseInt(last,2);
                result[0] = (byte)(i+8-strBinary.length());
                break;
            }else{
                result[index++] = (byte)Integer.parseInt(strBinary.substring(i,i+8),2);
                i+=8;
            }
        }

        writeToZipFile(result,targetPath);
    }

    /**
     * 将二进制,转换成字符串二进制
     * @param b
     * @return
     */
    public static String byte2Str(byte b){
        String s = Integer.toBinaryString(b);
        if(s.length()>8){
            s = s.substring(s.length()-8);
        }
        if(s.length()<8){
            s = String.format("%08d", Integer.parseInt(s));
        }
        return s;
    }

    /**
     * 解压文件
     * @param zipPath
     * @param unZipPath
     */
    public static void unZip(String zipPath,String unZipPath){
        byte[] zipBytes = readZipFile(zipPath);
        //解压之后的字符串
        StringBuilder unZipBinaryBuilder = new StringBuilder();
        for (int i = 1 ;i<zipBytes.length;i++){
            byte b = zipBytes[i];
            unZipBinaryBuilder.append(byte2Str(b));
        }
        String unZipBinary = unZipBinaryBuilder.toString();
        //如果有补位,把末尾的补位去掉
        int buWei = zipBytes[0];
        if(buWei>0){
            unZipBinary = unZipBinary.substring(0,unZipBinary.length()-buWei);
        }
        System.out.println("解压之后的字符串二进制数:"+unZipBinary);

        for (Map.Entry<Integer,String > entry:huffCodes.entrySet()){
            reverseHuffCodes.put(entry.getValue(),entry.getKey());
        }
        List<Byte> source = new ArrayList<>();

        int j = 0;
        for (int i = 0 ; j<unZipBinary.length();){
            for (j = i+1 ;j<=unZipBinary.length();j++){
                if(reverseHuffCodes.get(unZipBinary.substring(i,j))!=null){
                    source.add((byte)(int)reverseHuffCodes.get(unZipBinary.substring(i,j)));
                    i = j;
                    break;
                }
            }
        }
        byte[] b = new byte[source.size()];
        int a = 0;
        for(Byte by:source){
            b[a++]=by;
        }
        System.out.println("解压之后的长度:"+Arrays.toString(b));
        unZipWriteToFile(b,unZipPath);
    }

    public static void main(String[] args) {
        String source = "d:/temp/abc.txt";
        String target = "d:/temp/abc.zip";
        String source2 = "d:/temp/abc_bak.txt";
       //ZipFileUtil.zipFile(source,target);
        //System.out.println("压缩成功");
        ZipFileUtil.unZip(target,source2);
        System.out.println("解压成功");
    }
}

3、执行完之后,可以看文件的压缩情况

4、通过这个结果可以看到文件从98压缩到43,解压之后的文件还是98,也能够正常打开

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
综合实验: 1. 问题描述 利用哈夫曼编码进行通信可以大大提高信道利用率,缩短信息传输时间,降低传输成本。这要求在发送端通过一个编码系统对待传输据预先编码,在接收端将传来的据进行译码(复原)。对于双工信道(即可以双向传输信息的信道),每端都需要一个完整的编/译码系统。试为这样的信息收发站编写一个哈夫曼码的编/译码系统。 2. 基本要求 一个完整的系统应具有以下功能: (1) I:初始化(Initialization)。从终端读入字符集大小n,以及n个字符和n个权值,建立哈夫曼树,并将它存于文件hfmTree中。 (2) E:编码(Encoding)。利用已建好的哈夫曼树(如不在内存,则从文件hfmTree中读入),对文件ToBeTran中的正文进行编码,然后将结果存入文件CodeFile中。 (3) D:译码(Decoding)。利用已建好的哈夫曼树文件CodeFile中的代码进行译码,结果存入文件Textfile中。 (4) P:印代码文件(Print)。将文件CodeFile以紧凑格式显示在终端上,每行50个代码。同时将此字符形式的编码文件写入文件CodePrin中。 (5) T:印哈夫曼树(Tree printing)。将已在内存中的哈夫曼树以直观的方式(比如树)显示在终端上,同时将此字符形式的哈夫曼树写入文件TreePrint 中。 3. 测试据 用下表给出的字符集和频度的实际统计据建立哈夫曼树,并实现以下报文的编码和译码:“THIS PROGRAME IS MY FAVORITE”。 字符 A B C D E F G H I J K L M 频度 186 64 13 22 32 103 21 15 47 57 1 5 32 20 字符 N O P Q R S T U V W X Y Z 频度 57 63 15 1 48 51 80 23 8 18 1 16 1

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值