我在python中遇到struct.unpack
的主要问题。我有一个预定格式的二进制文件,可以用MATLAB或Python编写。
我可以用Python将二进制数据写入文件,并且可以毫无问题地读回数据。我也可以将相同的数据写入MATLAB的二进制文件,并在MATLAB中读回来没有问题。
当我从MATLAB写入数据并尝试用Python读取数据,或者用Python编写数据并尝试在MATLAB中读取数据时,我的问题出现了。
为简单起见,我们假设我将两个整数写入二进制文件(big-endian)。每个整数是4个字节。第一个整数是一个不大于4个字节的有效整数,第二个整数必须等于1,2或3。
首先,这是我在MATLAB中编写数据的方法:
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中阅读的内容:
fid=fopen('hello_matlab.test','rb');
first_data=fread(fid,1,'int');
second_data=fread(fid,1,'int');
fprintf('first data: %d\n', first_data);
fprintf('second data: %d\n', second_data);
fclose(fid);
>> first data: 8
>> second data: 1
现在,我在这里用Python编写数据:
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使用的字节数。编码:
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代码,这是新输出:
>> first data: 419430400
>> second data: 16777216
这很奇怪,所以我做了相反的事情。我看了看hello_matlab.test
时会发生什么。使用我当前的Python代码,这是新输出:
>> first data: 419430400
>> second data: 16777216
所以,有些奇怪的事情正在发生,但我不知道它是什么。另请注意,虽然这是大型项目的一部分,但我只是将我的代码的这些部分提取到一个新项目中,并使用这些结果测试上面的示例。我真的很困惑如何使这个文件可移植:(任何帮助将不胜感激。
答案 0 :(得分:1)
您可能对pandas hdf5商店感兴趣:
在Python中:
public class MainActivity extends Activity { TextView txtview; EditText edttxt; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); txtview=(TextView)findViewById(R.id.textView); edttxt=(EditText)findViewById(R.id.edittxt); String no=edttxt.getText().toString(); //this will get a string int no2=Integer.parseInt(no); //this will get a no from the string Button btn=(Button)findViewById(R.id.btn); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { txtview.setText(edttxt.getText()); } }); } }
在matlab中:
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])
但我不确定它是否有效,完全在浏览器中写道......
答案 1 :(得分:1)
问题在于endianness,即数字中位的顺序。您必须使用x86或x86-64计算机(因为这些是MATLAB支持的唯一计算机),并且这些是little-endian。但是,python >i
告诉它使用big-endian字节顺序。所以你正在使用相反的字节顺序,这使得两种语言读出完全不同的数字。
如果您只打算在x86或x86-64计算机上使用Python代码,或者只关心在同一台计算机上在MATLAB和Python之间发送数据,那么您可以完全省略字节顺序标记,使用本机字节顺序(所以i
而不是>i
)。如果您可能在powerpc系统上运行python,则可能需要手动指定little-endianess(<i
)。
对于这个例子,这似乎是唯一的问题。我想指出的是,如果您尝试一次读取和写入数据的数组/矩阵,那么numpy.fromfile
将更快更容易。