19

我用 Ruby 编写了一个简单的 Huffman 编码。作为输出,我有一个数组,例如:

["010", "1111", "10", "10", "110", "1110", "001", "110", "000", "10", "011"]

我需要在文件中写入然后读取它。我尝试了几种方法:

IO.binwrite("out.cake", array)

我得到一个简单的文本文件而不是二进制文件。

或者:

File.open("out.cake", 'wb' ) do |output|
  array.each do | byte |
       output.print byte.chr
  end
end

看起来它有效,但是我无法将它读入数组。

我应该使用哪种编码?

4

2 回答 2

28

我认为您可以使用Array#packString#unpack喜欢以下代码:

# Writing
a = ["010", "1111", "10", "10", "110", "1110", "001", "110", "000", "10", "011"]
File.open("out.cake", 'wb' ) do |output|
  output.write [a.join].pack("B*")
end

# Reading
s = File.binread("out.cake")
bits = s.unpack("B*")[0] # "01011111010110111000111000010011"

我不知道您对阅读结果的首选格式,我知道上述方法效率低下。但无论如何,您可以从结果中依次取“0”或“1”unpack来遍历您的霍夫曼树。

于 2013-05-30T11:04:11.963 回答
4

如果你想要位,那么你必须手动进行打包和解包。Ruby 或任何其他常用语言都不会为您做到这一点。

您的数组包含作为字符组的字符串,但您需要构建一个字节数组并将这些字节写入文件。

由此:["010", "1111", "10", "10", "110", "1110", "001", "110", "000", "10", "011"]

你应该构建这些字节:01011111 01011011 10001110 00010011

由于它只有四个字节,因此您可以将它们放入一个 32 位的十六进制数字010111110101101110001110000100115F5B8E13

您的代码的两个示例都做不同的事情。第一个将 Ruby 数组的字符串表示形式写入文件。第二个写入 32 个字节,每个字节为48('0') 或49('1')。

如果你想要位,那么你的输出文件大小应该只有四个字节。

阅读位操作以了解如何实现这一点。


这是一个草稿。我没有测试它。可能有问题。

a = ["010", "1111", "10", "10", "110", "1110", "001", "110", "000", "10", "011"]

# Join all the characters together. Add 7 zeros to the end.
bit_sequence = a.join + "0" * 7  # "010111110101101110001110000100110000000"

# Split into 8-digit chunks.
chunks = bit_sequence.scan(/.{8}/)  # ["01011111", "01011011", "10001110", "00010011"]

# Convert every chunk into character with the corresponding code.
bytes = chunks.map { |chunk| chunk.to_i(2).chr }  # ["_", "[", "\x8E", "\x13"]

File.open("my_huffman.bin", 'wb' ) do |output|
  bytes.each { |b| output.write b }
end

注意:当字符总数不能被 8 整除时,添加七个零来处理大小写。没有这些零,bit_sequence.scan(/.{8}/)将删除剩余的字符。

于 2013-05-29T20:02:15.653 回答