从Python解析用MATLAB编写的二进制文件,反之亦然

Parsing a binary file written in MATLAB from Python and vice versa

我在python中遇到struct.unpack的大麻烦。我有一个预定格式的二进制文件,可以用MATLAB或Python编写。

我可以用Python将二进制数据写入文件,然后再读回数据。我还可以将相同的数据从MATLAB写入二进制文件,然后在MATLAB中毫无问题地读回。

当我从MATLAB写入数据并尝试以Python读取数据时,或者在Python中写入数据并尝试以MATLAB读取数据时,就会出现我的问题。

为了简单起见,假设我正在将两个整数写入二进制文件(big-endian)。每个整数为4个字节。第一个整数是不超过4个字节的有效整数,第二个整数必须等于1、2或3。

首先,这是我如何在MATLAB中写入数据:

1
2
3
4
5
6
7
8
fid=fopen('hello_matlab.test','wb');
first_data=4+4;
second_data=1;

fwrite(fid,first_data,'int');
fwrite(fid,second_data,'int');

fclose(fid);

这是我在MATLAB中读到的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
fid=fopen('hello_matlab.test','rb');
first_data=fread(fid,1,'int');
second_data=fread(fid,1,'int');

fprintf('first data: %d\
'
, first_data);
fprintf('second data: %d\
'
, second_data);

fclose(fid);

    >> first data: 8
    >> second data: 1

现在,这是我如何用Python编写数据的方法:

1
2
3
4
5
6
7
8
fid=open('hello_python.test','wb')
first_data=4+4
second_data=1

fid.write(struct.pack('>i',first_data))
fid.write(struct.pack('>i',second_data))

fid.close()

这就是我如何用python读取数据的方法。还要注意,注释掉的部分有效(当读取用Python编写的文件时)。我本来以为计算struct.calcsize('>i')的方式会发生一些奇怪的事情,所以我删除了它,而是放入一个硬编码的常量INTEGER_SIZE来表示我知道MATLAB对其进行编码时使用的字节数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
INTEGER_SIZE=4

fid=open('hello_python.test','rb')

### FIRST WAY I ORIGINALLY READ THE DATA ###
# This works, but I figured I would try hard coding the size
# so the uncommented version is what I am currently using.
#
# first_data=struct.unpack('>i',fid.read(struct.calcsize('>i')))[0]
# second_data=struct.unpack('>i',fid.read(struct.calcsize('>i')))[0]

### HOW I READ DATA CURRENTLY ###
first_data=struct.unpack('>i',fid.read(INTEGER_SIZE))[0]
second_data=struct.unpack('>i',fid.read(INTEGER_SIZE))[0]

print"first data: '%d'" % first_data
print"second data: '%d'" % second_data

fid.close()

    >> first data: 8
    >> second data: 1

现在,假设我想在MATLAB中阅读hello_python.test。使用我当前的MATLAB代码,这是新的输出:

1
2
>> first data: 419430400
>> second data: 16777216

这很奇怪,所以我做了相反的事情。我看了看hello_matlab.test时会发生什么。使用我当前的Python代码,这是新的输出:

1
2
>> first data: 419430400
>> second data: 16777216

因此,发生了一些奇怪的事情,但我不知道这是什么。还要注意,尽管这是一个较大项目的一部分,但我只是将代码的这些部分提取到一个新项目中,并使用这些结果测试了上面的示例。我真的很困惑如何使该文件可移植:(任何帮助将不胜感激。


问题在于字节顺序,即数字中的位顺序。您必须在x86或x86-64计算机上(因为这是MATLAB唯一支持的计算机),并且它们是低端字节序的。但是,python >i告诉它使用大端字节顺序。因此,您使用相反的字节顺序,这使两种语言读出的数字完全不同。

如果您只打算在x86或x86-64计算机上使用Python代码,或者只考虑在同一台计算机上在MATLAB和Python之间发送数据,则可以完全不使用字节顺序标记并使用本机字节顺序(所以i而不是>i)。如果您可能在PowerPC系统上的python上运行,则可能需要手动指定低字节序()。

对于此示例,这似乎是唯一的问题。我想指出的是,如果您尝试一次读写数据的数组/矩阵,那么numpy.fromfile会更快,更容易。


您可能对熊猫hdf5商店感兴趣:

在Python中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
In [418]: df_for_r = pd.DataFrame({"first": np.random.rand(100),
   .....:                         "second": np.random.rand(100),
   .....:                         "class": np.random.randint(0, 2, (100,))},
   .....:                          index=range(100))
   .....:

In [419]: df_for_r.head()
Out[419]:
   class     first    second
0      0  0.417022  0.326645
1      0  0.720324  0.527058
2      1  0.000114  0.885942
3      1  0.302333  0.357270
4      1  0.146756  0.908535

In [420]: store_export = HDFStore('export.h5')

In [421]: store_export.append('df_for_r', df_for_r)

In [422]: store_export
Out[422]:
<class 'pandas.io.pytables.HDFStore'>
File path: export.h5
/df_for_r            frame_table  (typ->appendable,nrows->100,ncols->3,indexers->[index])

在Matlab中:

1
data = h5read('export.h5','/df_for_r');

但是我不确定它是否有效,完全在浏览器中编写了...