我在Ruby中编写了一个简单的霍夫曼编码。作为输出,我有一个数组,例如:
["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
看起来它的工作原理,但我无法将其读入数组。
我应该使用哪种编码?
答案 0 :(得分:28)
我认为您可以像以下代码一样使用Array#pack
和String#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"
我不知道您阅读结果的首选格式,我知道上述方法效率低下。但无论如何,你可以从unpack
的结果顺序取“0”或“1”来遍历你的霍夫曼树。
答案 1 :(得分:4)
如果你想要比特,那么你必须手动打包和解包。 Ruby和任何其他常用语言都不适合你。
您的数组包含字符组的字符串,但您需要构建一个字节数组并将这些字节写入文件。
来自:["010", "1111", "10", "10", "110", "1110", "001", "110", "000", "10", "011"]
你应该构建这些字节:01011111 01011011 10001110 00010011
由于它只有四个字节,因此您可以将它们放入一个01011111010110111000111000010011
十六进制的32位数字5F5B8E13
。
您的代码的两个示例都做了不同的事情。第一个将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}/)
将删除剩余的字符。