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



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

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

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

对于如何使用readunpack命令的任何帮助,我们将不胜感激。此外,如果在您提供的解决方案中,您可以对代码工作的原因做出非常简短的解释。

这个文件是由一个用Java编写的程序生成的。我之所以转储字节,是因为速度是关键,但如果通过添加分隔符字节或类似的东西,读取单独整数的过程变得更容易,我也会接受这个建议。

我建议使用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格式,它代表"Integer,32-bit unsigned,network(big-endian)byte order"(请参阅Ruby文档)。通过使用*,您可以告诉Ruby将字节转换为指定的类型,直到用完数据为止。以下是如何使用它:

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

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

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

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

以下是不使用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

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

这是ruby解决方案:

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}

最新更新