java - 将二进制值写入文件以进行霍夫曼编码

标签 java file compression huffman-code

我正在尝试使用霍夫曼编码实现文件压缩。目前,我将标题写为压缩文件的第一行,然后写入编码的二进制字符串(即具有二进制编码值的字符串)。

但是,我的文件大小并没有减小,而是在增加,因为对于每个字符(如“a”),我正在编写其对应的二进制文件,例如 01010001,这会占用更多空间。

如何以减少空间的方式将其写入文件?

这是我的代码

public void write( String aWord ) {

        counter++;
        String content;
        byte[] contentInBytes;

        //Write header before writing file contents
        if ( counter == 1 )
        {
            //content gets the header in String format from the tree
            content = myTree.myHeader;
            contentInBytes = content.getBytes();

            try {
                fileOutputStream.write(contentInBytes);
                fileOutputStream.write(System.getProperty("line.separator").getBytes());
            } catch (IOException e) {
                System.err.println(e);
            }
        }

        //content gets the encoded binary in String format from the tree
        content = myTree.writeMe(aWord);
        contentInBytes = content.getBytes();


            try {
                fileOutputStream.write(contentInBytes);
                fileOutputStream.write(System.getProperty("line.separator").getBytes());
            } catch (IOException e) {
                System.err.println(e);
            }
        }

示例输入文件:

abc
aef
aeg

压缩文件:

{'g':"010",'f':"011",'c':"000",'b':"001",'e':"10",'a':"11"}
11001000
1110011
1110010

最佳答案

正如我从评论中收集到的那样,您正在编写文本,但您真正想要实现的是编写二进制数据。您目前拥有的是一个很好的霍夫曼编码演示,但对于实际压缩数据是不切实际的。

要实现压缩,您需要将霍夫曼符号输出为二进制数据,您当前输出字符串“11”作为“a”,您只需要输出两位 11 .

我假设这是目前在 myTree.writeMe() 中编码的,您需要修改该方法以返回一个字符串,而是更适合二进制输出的东西,例如字节[].

如何执行此操作在一定程度上取决于树类的内部工作原理。我假设您在内部使用了一些 StringBuilder 并在循环输入时简单地添加编码的符号字符串。您将需要一个能够处理单个位的容​​器,而不是 StringBuilder。立即出现的唯一合适的类是 java.util.BitSet(在实践中,人们通常会为此编写一个专门的类,使用专门的 API 来快速执行此操作)。但为简单起见,现在让我们使用 BitSet。

在方法 writeMe 中,您原则上将执行以下操作:

 BitSet buffer = new BitSet();
 int bitIndex = 0;
 loop over input symbols {
     huff_code = getCodeForSymbol(symbol)
     foreach bit in huff_code {
         buffer.put(bitIndex++, bit)
     }
 }
 return buffer.toByteArray();

如何有效地执行此操作取决于您如何在内部定义霍夫曼码表。但是原理很简单,遍历代码,判断每个位置是1还是0,然后将它们放入连续索引处的BitSet中。

if (digits == '1') {
    buffer.set(bitIndex);
} else {
    buffer.clear(bitIndex);
}

您现在拥有霍夫曼编码数据。但是生成的数据将无法正确解压缩,因为您当前正在处理单词并且您没有写任何指示压缩数据实际结束的位置(您当前使用换行)。例如,如果您编码 3 次“a”,则 BitSet 将包含 11 11 11。那是 6 位,但是当您转换为 byte[] 时,它会被填充为 8 位:0b11_11_11_00。

那些额外的、不可避免的位会混淆你的减压。您将需要以某种方式处理此问题,方法是首先对数据中的符号数量进行编码,或者使用显式符号表示数据结束。

这应该让您知道如何继续想法。许多细节取决于您如何实现树类和编码符号。

关于java - 将二进制值写入文件以进行霍夫曼编码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33086677/

相关文章:

java - 我想破坏一个 swf ...然后 "uncorrupt"使其成为有效的 swf ...这可能吗?安卓Java

java - 使用 Hibernate 持久保存一个对象

java - 使用 java 独立应用程序连接到 BlazeDS

iphone - 如何在 iPhone 中查找 .pdf 或 .txt 或文件夹?

c# - 解压错误/压缩错误

java - 如何从 ArrayList 中删除特定数组

c++ - 如何在进程不被操作系统卡住或杀死的情况下将大量数字写入文件?

python解析文件

java - 压缩要通过 RMI 发送的 Java HashMap

android - Android中的视频压缩