将文件中的字节数据读入多个整数

时间:2013-12-15 12:40:57

标签: ruby file binary integer

我正在尝试从包含4字节整数的连续字节值的文件中读取数据。例如,整数123将存储在包含字节的文件中:

00000000 00000000 00000000 00000001 00000000 00000000 00000000 00000010 00000000 00000000 00000000 00000011 

我想阅读此内容并将每个数字分配给不同的变量,例如a = 1b = 2c = 3。我该怎么做?

如何使用readunpack命令,我们将不胜感激。此外,如果在您提供的解决方案中,您可以简要解释代码的工作原理。

该文件由Java编写的程序生成。我正在转储字节,因为速度是关键,但如果通过添加分隔符字节或类似内容来读取单独整数的过程变得更容易,我也会对该建议持开放态度。

3 个答案:

答案 0 :(得分:3)

我建议使用bindata gem:

require 'bindata'

class MyBinaryFormat < BinData::Record
  uint32 :a
  uint32 :b
  uint32 :c
end

io = File.open('/path/to/binary/file')
result = MyBinaryFormat.read(io)

puts result.a  # 1
puts result.b  # 2
puts result.c  # 3

如果您无法使用宝石,则可以使用String#unpack。您将需要使用N格式代表“整数,32位无符号,网络(大端)字节顺序”(请参阅​​Ruby Documentation)。通过使用*,您可以告诉Ruby将字节转换为指定的类型,直到数据耗尽为止。以下是您将如何使用它:

io = File.open('/path/to/binary/file')
a, b, c = io.read(12).unpack('N*')  #=> 1, 2, 3

如果您需要阅读更多内容,请相应地将参数调整为read(此处为3 * 4 = 12个字节)。

答案 1 :(得分:1)

以下是不使用unpack的方式。

将此行读入字符串(str)后:

arr = [] 
str = str.gsub(/\s/, '') #delete every space
len = str.length #get length of string
i = 0

while i<len #iterate over string until end(starting from 0)
    arr<<str[i...(i+16)].to_i(2) # "unpacking" 16 characters using range: 'string'[0...2] is 'st' & changing it into Integer with base 2(`to_i(base)`)
    i += 16 #going to next number(in your case 16 characters later)
end

当您以这样的“1 2 3”格式存储数字时,您的代码应该更快,因为(对于我的解决方案)您不需要使用gsub也不需要计算数字在哪里。 /> 不过,我建议您对从此主题中获得的代码进行基准测试。 如果您的目标是速度,可以尝试使用C扩展代码。

这是红宝石解决方案:

str = "1 2 3 4"
arr = str.split #split string on space (it's the same as `str.split(' ')` 
#result: ["1", "2", "3", "4"]
numbers = arr.collect{|el| el.to_i} #for each string in `arr` it calls `to_i` and store result in new array(not `arr`)
#[1, 2, 3, 4]

当然,你可以像这样做一行:

numbers = str.split.collect &:to_i 

或者像这样:

numbers = str.split.collect(|el| el.to_i}

答案 2 :(得分:1)

您可以使用特殊字符串运算符来计算二进制数。您的文件包含以下内容:

00000000 00000001 00000000 00000010 00000000 00000011 

代码如下:

# => ["00000000", "00000001", "00000000", "00000010", "00000000", "00000011"]
values =
IO.read( '1.1' ).split( /\s+/ ).map do| binary | # reading the file and splitting into an array by space
   i = -1
   binary.split( '' ).reverse.reduce( 0 ) do| sum, digit | # reduction binary into a digit
      i += 1
      sum + ( digit.to_i << i ) # sum by a digit
   end
end
=> [0, 1, 0, 2, 0, 3]

对于以下代码,将数组中先前覆盖的所有值传递到扩展参数的函数proc_func中:

def proc_func a, b, c, d, e, f
   puts a, b, c, d, e, f
end

proc_func *values

# 0
# 1
# 0
# 2
# 0
# 3