在 Java 中将霍夫曼编码的字符串写入文件时如何处理奇数字节?

问题描述

所以我正在尝试创建一个自适应霍夫曼编码算法,但遇到了一些我不知道如何解决的障碍。

我的算法完全按预期工作,除了一个小问题;当压缩结果不是每个字节都正好是 8 位时,我似乎无法弄清楚如何确保不会写入额外的字符。

举个例子;这是我输入文本的结尾片段

subscribe to our email newsletter to hear about new eBooks.

fa

这是同一文本经过编码然后解码后的结束片段

subscribe to our email newsletter to hear about new eBooks.

fa
as

额外的“as”字符是最终压缩位不是完整字节的一部分的结果;最后一个字节由位“0111”表示,程序内部将其识别为“00000111”,这会导致写入最后两个字符。除此之外,当我尝试将填充应用于该字节的末尾,使其被视为“01110000”时,结束片段如下所示。

subscribe to our email newsletter to hear about new eBooks.

fa
r

这稍微好一点,但额外的“r”字符被写入,因为这种编码的“r”的代码是“0000”,导致这种复杂化。

我该如何避免这种情况?

如果这意味着什么,为了获取位,我正在使用以下代码块操作一个包含 1 和 0 序列的编码字符串。

split 是一个字符串数组,其中字符串被拆分为 8 个字符,而 list 是一个 ArrayList,其中包含存储的整数列表,以便稍后输出为二进制表示的字符串。

String[] split = frankenstein.encodedString.split("(?<=\\G.{8})");
for (int i = 0; i < split.length; i++) {

    String str = split[i];
                
    //Adds 0 padding at the end of the bits if it's necessary
    if (i == split.length - 1) {
        if (str.length() != 8) {
            for (int j = str.length(); j < 8 ;j++) 
                str += "0";
        }          
    }

list.add(Integer.parseInt(str,2));
}

解决方法

要么 a) 在编码消息之前发送要解码的字符数,要么 b) 包括一个唯一的流结束符号作为您正在编码的最后一个符号。后者的一个例子是,如果您要编码范围为 0..255 的字节,请在末尾添加一个值为 256 的符号,该符号不能出现在前面的数据中。