因此,我使用MATLAB创建了一个简单的二进制文件,其结构如下:
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 :(得分: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\x00@\x00\x00\x00\x00\x00\x00\x08@\x00\x00\x00\x00\x00\x00\x10@\x00\x00\x00\x00\x00\x00\x14@\x00\x00\x00\x00\x00\x00\x18@'
Container:
record_type = 2
rows = 2
columns = 3
vector = [
1.0
2.0
3.0
4.0
5.0
6.0
]