2016-08-19 68 views
0

所以,我创建使用MATLAB简单的二进制文件,该文件具有以下结构:读取预格式的二进制文件在Python

file.test 
-------- 
[record_type] = 1 % 'int', 4 bytes, record_type = 1 means a string is read next 
[string_length] = len(str) % 'int', 4 bytes, tells us how many bytes to read 
[string] = '...' % 'char', the number of bytes in string length 

[record_type] = 2 % 'int', 4 bytes, record_type = 2 means a vector will be read 
[rows] = size(vector,1) % 'int', 4 bytes 
[columns] = size(vector,2) % 'int', 4 bytes 
[vector] = (vector) % 'double' 

我可以在MATLAB用下面的代码读取该文件回(这是只是代码的读取部分,我有错误检查和其他东西):

fid=fopen('file.test','rb') 
record_names={} 
record_data=[] 

while ~feof(fid) 
    [record_name_type,count]=fread(fid,1,'int'); 
    if count == 0 % reached eof 
     break; 
    end 
    record_name_length=fread(fid,1,'int'); 
    record_names{end+1}=char(fread(fid,record_name_length,'char')'); 
    % read vector 
    record_type=fread(fid,1,'int'); 
    rows=fread(fid,1,'int'); 
    cols=fread(fid,1,'int'); 
    record_data{end+1}=fread(fid,[rows,cols],'double'); 
end 

所以,我不得不此相同的功能转化为Python 2.7版。不幸的是,这证明是非常困难的。我不能仅仅调用fread并告诉它我想要读取多少个元素或字节。我曾尝试下面的代码与structs:现在

def read_file(filename): 
    # checking to see if file exists/other checks happen 
    fid=open(filename,'rb') 
    record_data=[] 
    record_names=[] 
    result=read_record(fid) 
    while result: 
     record_names.append(result['record_name']) 
     record_names.append(result['data']) 
     result=read_record(fid) 
    fid.close() 
    return (record_names, record_data) 

def read_record(fid): 
    try: 
     # read name 
     record_name_type = struct.unpack('i',fid.read(struct.calcsize('i')))[0] 
     record_name_len = struct.unpack('i',fid.read(struct.calcsize('i')))[0] 
     record_name = struct.unpack('s',fid.read(record_name_len))[0] 
     # read vector 
     record_type = struct.unpack('i',fid.read(struct.calcsize('i')))[0] 
     rows = struct.unpack('i',fid.read(struct.calcsize('i')))[0] 
     cols = struct.unpack('i',fid.read(struct.calcsize('i')))[0] 
     record_data = numpy.array(struct.unpack('%dd' % rows,fid.read(rows*struct.calcsize('d'))),dtype=float) 
     # store into result and return 
     result=OrderedDict() 
     result['record_name']=record_name 
     result['data']=record_data 
    except struct.error as e: 
     print e 
     result=None 
    return result 

在Python运行我的方法的时候,我得到以下错误:

unpack requires a string argument of length 1其从except strcut.error as e部分即将到来。我有一种感觉,我错误地阅读矢量,但我不知道我是如何错误地阅读字符串。

有谁知道更简单的方法来阅读这个二进制文件?或者是否有一些教程可以帮助我理解如何在Python中正确使用结构?我真的很陌生,尤其是Python领域。

+0

声明:'record_name = struct.unpack( 'S',fid.read(record_name_len))[0]'引起了例外。您应该在格式参数中指定字符串的长度:''%ds'%record_name_len'。 – acw1668

+0

@ acw1668但是我怎么读它?做'record_name = struct.unpack('%ds'%record_name_len,fid.read(record_name_len))[0]'返回一个TypeError:解压期望的2个参数,得到3.'如果我只放入'record_name_len',它只知道使用'read()'?我有点困惑D: – Alex

回答

0

可以使用Construct

from construct import * 

MyData = Struct(
    "MyData", 
    SBInt32("record_type"), 
    Switch("value", lambda ctx: ctx.record_type, 
    { 
     1: Embed(Struct(
      'string_data', 
      SBInt32("string_length"), Bytes("string", lambda ctx: ctx.string_length))), 
     2: Embed(Struct(
      'vector_data', 
      SBInt32("rows"), SBInt32("columns"), 
      Array(lambda ctx: ctx.rows * ctx.columns, LFloat64("vector")))) 
    } 
    ) 
) 

s = MyData.build(Container(record_type=1, string_length=4, string='abcd')) 
print(repr(s)) 
print(MyData.parse(s)) 

s = MyData.build(Container(record_type=2, rows=2, columns=3, vector=[1, 2, 3, 4, 5, 6])) 
print(repr(s)) 
print(MyData.parse(s)) 

输出:

'\x00\x00\x00\x01\x00\x00\x00\x04abcd' 
Container: 
    record_type = 1 
    string_length = 4 
    string = 'abcd' 
'\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\[email protected]\x00\x00\x00\x00\x00\x00\[email protected]\x00\x00\x00\x00\x00\x00\[email protected]\x00\x00\x00\x00\x00\x00\[email protected]\x00\x00\x00\x00\x00\x00\[email protected]' 
Container: 
    record_type = 2 
    rows = 2 
    columns = 3 
    vector = [ 
     1.0 
     2.0 
     3.0 
     4.0 
     5.0 
     6.0 
    ]