利用哈夫曼压缩文件

在这里插入图片描述

package com.jason.huffman;

import java.io.*;
import java.util.*;
import java.util.zip.ZipOutputStream;

public class HuffmanCodesDemo {
    public static void main(String[] args) {
//        String str = "iiii loveeee youuuuu";
//        byte[] zipArr = FillBox.getLetterAndCal(str);
//        byte[] bytess = FillBox.releaseZip(zipArr);
//        System.out.println(new String(bytess));

        InOutResourse.getInput("C:\\testzip\\9.png","C:\\testzip\\9.zip");
        InOutResourse.outputZip("C:\\testzip\\9.zip","C:\\testzip\\90.png");
    }
}

class InOutResourse{
    //压缩代码
    public static void getInput(String resource,String dest)  {
        FileInputStream fs =null;
        FileOutputStream ofs= null;
        ObjectOutputStream oos = null;
        try {
            fs = new FileInputStream(resource);
            byte[] bytes = new byte[fs.available()];
            fs.read(bytes);
            byte[] lAC = FillBox.getLetterAndCal(bytes);
            Map<Byte,String> mapss = FillBox.maps;
            ofs = new FileOutputStream(dest);
            oos = new ObjectOutputStream(ofs);
            oos.writeObject(lAC); //压缩后的编码
            oos.writeObject(mapss);//编码对照表
        } catch (Exception e) {
            System.out.println("失败");
            e.printStackTrace();
        }finally {
            try {
                oos.close();
                ofs.close();
                fs.close();
            } catch (Exception e) {
                System.out.println("失败");
                e.printStackTrace();
            }

        }

    }

    public static void outputZip(String resource,String dest){

        FileInputStream fs =null;
        FileOutputStream ofs= null;
        ObjectInputStream ois = null;
        try {
          fs = new FileInputStream(resource);
          ois = new ObjectInputStream(fs);
          byte[] by=(byte[]) ois.readObject();
          Map<Byte,String> mapg = (Map<Byte,String>) ois.readObject();
          FillBox.maps = mapg;
          byte[] byteg = FillBox.releaseZip(by);
          ofs = new FileOutputStream(dest);
          ofs.write(byteg);

        } catch (Exception e) {
            System.out.println("失败");
            e.printStackTrace();
        }finally {
            try {
                    ofs.close();
                    ois.close();
                    fs.close();
            } catch (Exception e) {
                System.out.println("失败");
                e.printStackTrace();
            }

        }


    }


}




class FillBox{

    static Map<Byte,String> maps = new HashMap<>();
    static int num=0;

    //解压
    public static byte[] releaseZip(byte[] ziparr){
       //1、将ziparr字节数组 转换成 二进制
        StringBuilder sb = new StringBuilder();
        String s = null;
        String s1 = null;
       for (int i = 0;i<ziparr.length;i++){
           if (ziparr[i] >= 0){
               //如果是最后一个字节
               if (i == ziparr.length - 1){
                   s = Integer.toBinaryString(ziparr[i]);
                   int len = s.length();
                   //num记录的是最后一个字节实际的位数,不足则在前面补零
                   if (len < num){
                       int k = num - len;
                       int j = 0;
                       StringBuilder gg = new StringBuilder();
                       while ( j < k){
                           gg.append("0");
                           j++;
                       }
                       s = gg + s;
                   }

               }else { //不是最后一个字节
                   int a;
                   //保证 a 转成二进制时 一定是八位的
                   a = ziparr[i] | 256;
                   s1 = Integer.toBinaryString(a);
                  s = s1.substring(1);
               }

           }else{//如果是负数那么一定就是八位
                s1 = Integer.toBinaryString(ziparr[i]);
                s = s1.substring(s1.length() - 8);
           }
           sb.append(s);
       }

    //   利用sb和maps 还原
    //   1、先将maps反转,
        Map<String,Byte> maps2 = new HashMap<String,Byte>();
        for (Map.Entry<Byte,String> entry : maps.entrySet()){
            maps2.put(entry.getValue(),entry.getKey());
        }

     //2、 查表
        int  count = 0;
        int index = 0;

        List<Byte> list = new ArrayList<>();
        while(count < sb.length()){
            int i = 0;
            while (count+i<sb.length()){

             String key = sb.substring(count,count+i+1);

                if (maps2.get(key)!=null){
                    list.add(maps2.get(key));
                    count = count+i+1;
                    break;
                }else {
                    i++;
                }
            }
        }

        byte[] by=new byte[list.size()];
        for (int i = 0;i<list.size();i++){
            by[i] = list.get(i);
        }
        return by;
    }



    //该方法是算出字符串中每个字母出现的次数(权重)
    public static byte[] getLetterAndCal(byte[] bytes){

        List<Letter> list = new ArrayList<>();
        Map<Byte,Integer> map = new HashMap<>();
        for (byte b : bytes){
            Integer integer = map.get(b);
            //如果该字母没有出现过,直接加入到map中
            if (integer == null){
                map.put(b,1);
            }else{//反之,把value++
                map.put(b,integer+1);
            }
        }

        //遍历map集合,加入到list集合中
        for (Map.Entry<Byte,Integer> entry : map.entrySet()){
            list.add(new Letter(entry.getKey(),entry.getValue()));
        }

        //加入到list集合后,就知道了每个结点的字母和权重,这样就可以开始构造一个哈夫曼树了
        Letter head = createHuffmanTree(list);
        //获取到了编码表,并存在maps域里
        huffmanCodeTab(new StringBuilder(),"",head);
        byte[] zip = getZip(bytes);
        return zip;

    }

    // 根据原本的字母字节数组 与 每个字母对应的编码,补齐来
    public  static byte[] getZip(byte[] by){

        //获取了字母字节数组的所有编码
        StringBuilder stringBuilder = new StringBuilder();
        for (byte b : by){
            stringBuilder.append(maps.get(b));
        }

//        System.out.println(stringBuilder);
        //以八位(即,八个二进制数字)为一个字节,分成len个字节
        int len = 0;
        if (stringBuilder.length() % 8 == 0 ){
            len = stringBuilder.length() / 8;
        }else {
            len = stringBuilder.length() / 8 + 1;
        }

        //新建一个字节数组,用于存放最终的字母字节数组 压缩过后的 字节数组
        byte[] huffmanByte = new byte[len];
        int index = 0;
        for (int i = 0 ; i < stringBuilder.length() ; i=i+8 ){
            String substr;
            if (i + 8 > stringBuilder.length()){
                num = stringBuilder.length() - i;
                substr = stringBuilder.substring(i);
            }else {
                substr = stringBuilder.substring(i, i + 8);
            }

            byte i1 = (byte)Integer.parseInt(substr, 2);
            huffmanByte[index] = i1;
            index ++;
        }
        return huffmanByte;
    }


    public static Letter createHuffmanTree(List<Letter> list){
        while (list.size() > 1){

            Collections.sort(list);

            Letter letter1 = list.get(0);
            Letter letter2 = list.get(1);

            Letter root = new Letter(null,letter1.weight+letter2.weight);
            root.leftLetter = letter1;
            root.rightLetter = letter2;
            list.remove(letter1);
            list.remove(letter2);
            list.add(root);

        }
        return list.get(0);
    }


    public static void preorder(Letter letter){
        System.out.println(letter);
        if (letter.leftLetter != null)
            preorder(letter.leftLetter);
        if (letter.rightLetter != null)
            preorder(letter.rightLetter);

    }

    public static void huffmanCodeTab(StringBuilder stringBuilder,String code,Letter root){
        StringBuilder stringBuilder1 = new StringBuilder(stringBuilder);
        stringBuilder1.append(code);

        if (root != null){
            if (root.letter == null){
                huffmanCodeTab(stringBuilder1,"0",root.leftLetter);//左递归
                huffmanCodeTab(stringBuilder1,"1",root.rightLetter);
            }else {
                maps.put(root.letter,stringBuilder1.toString());
            }
        }


    }
}


class Letter implements Comparable<Letter>{
    Byte letter;//字母
    int weight;//权重
    Letter rightLetter;
    Letter leftLetter;
    public Letter(Byte letter,int weight){
        this.letter = letter;
        this.weight = weight;
    }

    @Override
    public String toString() {
        return "Letter{" + "letter=" + letter + ", weight=" + weight + '}';
    }

    @Override
    public int compareTo(Letter o) {
        return this.weight - o.weight;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值