Проблема чтения двоичного файла Python - PullRequest
3 голосов
/ 02 июля 2010

Я пытаюсь прочитать двоичный файл (который представляет собой матрицу в Matlab) в Python.Но у меня возникают проблемы с чтением файла и преобразованием байтов в правильные значения.

Бинарный файл состоит из последовательности 4-байтовых чисел.Первые два числа - это количество строк и столбцов соответственно.Мой друг дал мне функцию Matlab, которую он написал, которая делает это с помощью fwrite.Я хотел бы сделать что-то вроде этого:

f = open(filename, 'rb')
rows = f.read(4)
cols = f.read(4)
m = [[0 for c in cols] for r in rows]
r = c = 0
while True:
    if c == cols:
        r += 1
        c = 0
    num = f.read(4)
    if num:
        m[r][c] = num
        c += 1
    else:
        break

Но всякий раз, когда я использую f.read (4), я получаю что-то вроде '\ x00 \ x00 \ x00 \ x04' (этот конкретный пример должен представлять4), и я не могу понять, преобразовать ли это в правильное число (использование int, hex или чего-то подобного не работает).Я наткнулся на struct.unpack, но это, похоже, не очень помогло.

Вот пример матрицы и соответствующего двоичного файла (как это выглядит, когда я читаю весь файл, используя функцию python f.прочитайте () без какого-либо параметра размера), что для него создана функция Matlab:

4     4     2     4
2     2     2     1
3     3     2     4
2     2     6     2

'\x00\x00\x00\x04\x00\x00\x00\x04@\x80\x00\x00@\x00\x00\x00@@\x00\x00@\x00\x00\x00@\x80\x00\x00@\x00\x00\x00@@\x00\x00@\x00\x00\x00@\x00\x00\x00@\x00\x00\x00@\x00\x00\x00@\xc0\x00\x00@\x80\x00\x00?\x80\x00\x00@\x80\x00\x00@\x00\x00\x00'

Таким образом, первые 4 байта и 5-8-й байты должны быть равны 4, поскольку матрица имеет размер 4x4.и тогда должно быть 4,4,2,4,2,2,2,1 и т. д. ...

Спасибо, ребята!

Ответы [ 2 ]

7 голосов
/ 02 июля 2010
rows = f.read(4)
cols = f.read(4)

оба имени теперь связаны с 4-байтовыми строками. Чтобы превратить их в целые числа,

import struct

rowsandcols = f.read(8)
rows, cols = struct.unpack('=ii', rowsandcols)

См. документы для struct.unpack.

2 голосов
/ 02 июля 2010

Я посмотрел немного больше в вашей проблеме, так как я никогда не использовал struct, так что это была хорошая учебная деятельность. Оказывается, здесь есть пара поворотов - сначала числа хранятся не как 4-байтовые целые числа, а как 4-байтовые числа с плавающей точкой в ​​формате с прямым порядком байтов. Во-вторых, если ваш пример верен, то матрица была сохранена не так, как можно было бы ожидать - по строкам, а не по столбцам. Например. это было выведено так (псевдокод):

for j in cols:
  for i in rows:
    write Aij to file

Так что мне пришлось перенести результат после прочтения. Вот код, который вам нужен на примере:

import struct 

def readMatrix(f):
    rows, cols = struct.unpack('>ii',f.read(8))
    m = [ list(struct.unpack('>%df' % rows, f.read(4*rows)))
             for c in range(cols)
        ]
    # transpose result to return
    return zip(*m)

И вот мы проверяем это:

>>> from StringIO import StringIO
>>> f = StringIO('\x00\x00\x00\x04\x00\x00\x00\x04@\x80\x00\x00@\x00\x00\x00@@\x00\x00@\x00\x00\x00@\x80\x00\x00@\x00\x00\x00@@\x00\x00@\x00\x00\x00@\x00\x00\x00@\x00\x00\x00@\x00\x00\x00@\xc0\x00\x00@\x80\x00\x00?\x80\x00\x00@\x80\x00\x00@\x00\x00\x00')
>>> mat = readMatrix(f)
>>> for row in mat:
...     print row
...     
(4.0, 4.0, 2.0, 4.0)
(2.0, 2.0, 2.0, 1.0)
(3.0, 3.0, 2.0, 4.0)
(2.0, 2.0, 6.0, 2.0)
...