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

1、在这里只有工具类,依赖的树节点和树的类,见另一篇博客(https://blog.youkuaiyun.com/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,也能够正常打开

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值