Python二进制文件读取问题

时间:2010-07-01 22:37:16

标签: python matlab file-io binary

我正在尝试在Python中读取二进制文件(表示Matlab中的矩阵)。 但是我无法读取文件并将字节转换为正确的值。

二进制文件由一系列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),我无法弄清楚将其转换为正确的number(使用int,hex或类似的东西不起作用)。我偶然发现了struct.unpack,但这似乎没什么帮助。

这是一个示例矩阵和相应的二进制文件(当我使用python函数f.read()读取整个文件时没有任何大小的参数),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 个答案:

答案 0 :(得分:7)

rows = f.read(4)
cols = f.read(4)

这两个名称现在绑定到4字节字符串。把它们变成整数,

import struct

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

struct.unpackthe docs

答案 1 :(得分:2)

我在你的问题中看得更多,因为我以前从未使用过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)