2013-12-15 4 views
1

Я пытаюсь прочитать данные из файла, содержащего непрерывные байтовые значения для 4 байтовых целых чисел. Так, например, целые числа 1, 2, 3 будет храниться в файле, содержащем байты:Чтение байт данных из файла в несколько целых чисел

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

Я хочу, чтобы прочитать это и назначить каждый номер на другой переменной, например a = 1, b = 2 и c = 3. Как мне это сделать?

Любая помощь будет оценена с использованием команд read и unpack. Кроме того, если в решении, которое вы даете, вы можете дать краткое объяснение, почему ваш код работает.

Этот файл создается программой, написанной на Java. Я сбрасываю байты, потому что скорость является ключевой, но если процесс чтения в отдельные целые числа становится проще, добавив байт-разделитель или что-то подобное, я тоже буду открыт для этого предложения.

+0

имеет мой ответ был полезен? –

ответ

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} 
+0

Я копирую и вставляю свой ответ на сообщение выше: Итак, они используют строковые операторы? Интересно, тогда проще ли просто хранить эти числа в виде строк вместо байтовых значений (так на самом деле хранить «2» вместо 00000010)? Как я уже сказал, файл создается программой, которую я управляю, поэтому я могу ее изменить, чтобы вывести номер в любом формате. Мои единственные критерии - то, что это должно быть как можно быстрее. –

+0

@PratikThaker см. Редактировать –

3

Я рекомендую использовать bindata перл:

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 байт), соответственно.

+0

Ah - Я забыл упомянуть - я хочу попытаться сделать это, не используя драгоценный камень. Причина в том, что мне нужно использовать проприетарный API Ruby, и это не поддерживает драгоценные камни. –

+0

@PratikThaker см. Мое редактирование о том, как использовать встроенный метод 'unpack'. –

+0

Btw, если вы можете запустить ruby-код, вы можете запускать драгоценные камни. Возможно, это будет вариант для продажи драгоценного камня в ваш проект, если вы сможете воспользоваться им. –

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] 

И следующий код проходит все значения stroed Previouly в массиве в функцию 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 
+0

Хм - это интересно. Значит, они используют строковые операторы? Интересно, тогда проще ли просто хранить эти числа в виде строк вместо байтовых значений (так на самом деле хранить «2» вместо 00000010)? Как я уже сказал, файл создается программой, которую я управляю, поэтому я могу ее изменить, чтобы вывести номер в любом формате. Мои единственные критерии - то, что это должно быть как можно быстрее. –

+0

Вы должны измерить время для всех предлагаемых методов. Но основной причиной использования рубина является не скорость, а удобство использования и простота кодирования. Чтобы сделать быстрый быстрый код, люди используют c, или, например, языки, подобные схеме (см. STALin). –

+0

Является ли это двоичным кодом? почему shell вы храните «2» вместо 00000010? –

Смежные вопросы