winRAR真难用,我决定自创一个(化神期) 解压

  化神期简介

化身期主要阐述的是解压的思路和解压的代码实现分析

提供完整代码,代码在筑基期中

博主空间https://blog.csdn.net/JOElib?type=lately结丹期https://blog.csdn.net/JOElib/article/details/123905069?spm=1001.2014.3001.5501
元婴期https://blog.csdn.net/JOElib/article/details/123913609?spm=1001.2014.3001.5501


目录

解压思想🐼

代码实现与分析🐼

1.建立一个用于将byte变成哈夫曼的方法🐻 

代码分析:🐨 

2.创建一个解压的方法🐻 

代码分析:🐨 

3.封装代码🐻

代码分析:🐨

结论🐼


解压思想🐼

  1.  利用哈夫曼编码表,把对应的byte类型数据转换为二进制字符串
  2.  将二进制字符串拼接起来,形成一个哈夫曼编码字符串
  3.  将哈夫曼编码表对应的Map的key和value反转
  4.  根据新哈夫曼编码表将哈夫曼编码字符串解压成原来的内容(byte数组)
  5.  将byte数组转换为原来的字符串即可

代码实现与分析🐼

1.建立一个用于将byte变成哈夫曼的方法🐻 

public static String byteToString(byte b,boolean flag) {
        int temp = b;
        temp |= 256;
        String str = Integer.toBinaryString(temp);
        if (flag) {
            return str.substring(str.length() - 8);
        }
        return str.substring(str.length() - lastCount);
    }

代码分析:🐨 

  1. 参数列表:
    1. b代表的是压缩后的byte[]数组中的元素,即将该元素转化为哈夫曼编码
    2. flag为布尔标记,用于判断是否为最后一个元素
  2. 第一步,我们要利用自动类型转换,将b赋值给temp
  3. 将temp|=256(重点)
    1. 首先,temp自动类型转换的原因出现在这个地方,因为256对应的二进制是"1 0000 0000"共9位,如果我们直接用b(byte)类型,由于我们知道1byte = 8bit 导致这个语句无意义
    2. 其次,哈夫曼编码是以二进制补码的形式存储在计算机的,故哈夫曼编码就是补码
    3. 再者,当整形十进制数大于0时,调用toBinaryString()方法没有8位
      1. 假设,一个压缩后的正数10,调用该方法后变成"1010"
    4. 我们通过元婴期了解到,哈夫曼编码前面是每8位取一次,形成一个整形十进制数,如果不是最后一次取出的话,该哈夫曼编码长度一定为8
      1. 如果恰好是正数,通过3.1可知最终变成'1010",不满8位,即所取得不是我们想要的哈夫曼编码
      2. 后果:解压失败
    5. 通过tmep |= 256 能有效的保证正数一定有9位,保障了8位数据不丢失,并保障了数据的完整性,起补位的作用
  4. toBinaryString()方法
    1. 将整形十进制数转换为二进制补码即哈夫曼编码,注意,由于该方法是Integer里面的,所以,其补码获取的是32位的
    2. 所以后面涉及截断操作(即强制类型转换)
  5. 根据flag,判断是否为最后一个元素(false表示是最后一个元素)
    1. 如果不是,则截断后8位,即str.substring(str.length() - 8);
      1. 长度-8开始截断即后8位
    2. 如果是,则需要考虑需要截断多少位
      1. 因为最后一次取,不一定取到8位
      2. 借助最后一次所赋予的属性lastCount,就能明确知道多少位了,这就是元婴期中的坑在"6.创建一个压缩的方法🐻"中出现了lastCount = str.length记录了该长度
  6. 通过上述方法就可以得到对应的无损哈夫曼编码字符串

2.创建一个解压的方法🐻 

 public static byte[] decode(byte[] huffmanCodesBytes,Map<Byte,String> huffmanCodes) {
        var strBil = new StringBuilder();
        for (int i = 0; i < huffmanCodesBytes.length; i++) {
            boolean flag = (i != huffmanCodesBytes.length -1);
            strBil.append(byteToString(huffmanCodesBytes[i],flag));
        }
        var map = new HashMap<String,Byte>();
        for (var entry : huffmanCodes.entrySet()) {
            map.put(entry.getValue(),entry.getKey());
        }
        var list = new ArrayList<Byte>();
        for (int i = 0; i < strBil.length();) {
            Byte b ;
            var count = 1;
            while ((b = map.get(strBil.substring(i, i + count))) == null) {
                count++;
            }
            list.add(b);
            i += count;
        }
        var content = new byte[list.size()];
        for (int i = 0; i < content.length; i++) {
            content[i] =list.get(i);
        }
        return content;
    }

代码分析:🐨 

  1. 参数列表:
    1. byte[]为压缩后的byte[]数组,Map<Byte,String>为哈夫曼编码表
  2. new一个StringBuilder,用于字符串拼接作用,形成一个哈夫曼编码字符串
  3. 建立一个for循环,遍历byte数组里面的元素,将byte数组里面的每一个byte变成对应的哈夫曼编码,即调用上述的byteToString()方法
    1. 注意:如果到了最后一个元素,根据之前所述,最后一个元素的时候需要将flag改为false,即 i != huffmanCodesBytes.length -1
  4. 创建一个新的Map集合,用于存放新的哈夫曼编码表
    1. 由我们的知识可以知道,我们可以通过key从而得到对应的value
    2. 之前压缩的时候是通过ASCII获得对应的赫夫曼字符串,ASCII在key上,赫夫曼编码在value上
    3. 为了实现由赫夫曼编码字符串获得对应的ASCII,所以要将他们对调
  5. 利用增强for循环,在调用entrySet方法,将Map集合转换成Set集合,分别调用getKey()和getValue()方法,就能有效对调
  6. new一个结合List,用于存放ASCII码,原因是好管理
  7. 重点:由于我们想要从哈夫曼编码字符串中还原成对应的ASCII,所以我们要遍历该字符串
    1. 创建一个包装类Byte,用于存放取出来的ASCII  注意:不可以使用byte(基本数据类型)
    2. 创建一个计数器count,并初始化为1
    3. 创建一个while循环,里面的布尔表达式写(b = map.get(strBil.substring(i, i + count))) == null
      1. 解释:我们调用subString()方法,进行字符串截断,即截断[i,i+count)
      2. 如果我们获取的值为空,说明赫夫曼编码没有截全,所以要进入循环,使得count++,截取多一个,再进行获取,知道获取成功,说明截全了,退出循环
      3. 将获取的值加入集合中
      4. 再将i+=count,表示开始截取下一个哈夫曼编码(注意:这样写才可以保证不重叠读取)
    4. 通过不断的进行以上操作,就能把所有的元素都还原了
    5. 注意:更新表达式是空的,不能写任何东西
  8. 通过集合元素个数即list.size()创建对应的byte[]数组
  9. 通过循环将元素放回byte[]数组,最后返回byte[]数组,解压成功

3.封装代码🐻

    public static String decode(byte[] huffmanBytes) {
        return new String(decode(huffmanBytes,HUFFMAN_CODES));
    }

代码分析:🐨

  1. 由于我们最终想要的是字符串,所以我们不妨来个方法重载,将返回值类型改为String
    1. 由于手动穿哈夫曼编码表太傻了,所以不写了
    2. 根据上述要求就写出了方法重载 

结论🐼

        相信看到这里的小伙伴都充满坎坷,如果四期全懂了,离我们压缩和解压文件就不远了,如果有不懂的地方和错误的地方,可以随时评论区留言,下一期也是最后一期,炼虚期!

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爪哇土著、JOElib

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值