2016-08-21 3 views
0

Ich habe große Probleme mit struct.unpack in Python. Ich habe eine Binärdatei mit einem vorgegebenen Format, das entweder in MATLAB oder in Python geschrieben werden kann.Analysieren einer in MATLAB geschriebenen Binärdatei von Python und umgekehrt

Ich kann Binärdaten in eine Datei in Python schreiben und die Daten ohne Probleme zurück lesen. Ich kann dieselben Daten auch von MATLAB in eine Binärdatei schreiben und sie ohne Probleme in MATLAB zurücklesen.

Mein Problem kommt, wenn ich entweder die Daten aus MATLAB schreibe und versuche, es wieder in Python zu lesen, oder wenn ich die Daten in Python schreibe und versuche, es wieder in MATLAB zu lesen.

Zur Vereinfachung sagen wir, ich schreibe zwei ganze Zahlen in eine Binärdatei (Big-Endian). Jede Ganzzahl ist 4 Bytes. Die erste Ganzzahl ist eine gültige ganze Zahl nicht größer als 4 Bytes, und die zweite ganze Zahl gleich sein muss entweder 1, 2 oder 3.

Als erstes ist hier, wie ich meine Daten in MATLAB schreiben:

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); 

Und hier ist, wie ich das zurück in MATLAB lesen:

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 

Nun, hier ist, wie ich die Daten in Python schreiben:

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() 

Und hier ist, wie ich diese Daten in Python wiedergelesen habe. Beachten Sie auch, dass der auskommentierte Teil funktionierte (beim Lesen von in Python geschriebenen Dateien). Ursprünglich dachte ich, etwas seltsam war mit der Art und Weise geschieht struct.calcsize('>i') berechnet wurde, so dass ich es entnommen und stattdessen eine hartcodierte Konstante, INTEGER_SIZE, um die Menge von Bytes darstellen Ich wusste MATLAB verwendet hatte, als es kodiert:

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 

Jetzt sagen wir, ich möchte hello_python.test in MATLAB lesen. Mit meinem aktuellen MATLAB-Code, hier ist die neue Ausgabe:

>> first data: 419430400 
>> second data: 16777216 

Das ist seltsam, also habe ich das Gegenteil getan. Ich habe geschaut, was passiert, wenn ich hello_matlab.test lese. Mit meinem aktuellen Python-Code, hier ist die neue Ausgabe:

>> first data: 419430400 
>> second data: 16777216 

Also, etwas Seltsames passiert, aber ich weiß nicht, was es ist. Beachten Sie bitte, obwohl dies Teil eines größeren Projekts ist, habe ich nur diese Teile meines Codes in ein neues Projekt extrahiert und das obige Beispiel mit diesen Ergebnissen getestet. Ich bin wirklich verwirrt, wie diese Datei tragbar machen :(Jede mögliche Hilfe würde geschätzt

+0

Ich sehe nichts im MATLAB-Code, der anzeigen würde, dass Sie die Werte im Big-Endian-Format schreiben; Ich vermute, dass sie im Little-Endian-Format geschrieben sind, also wenn Sie mit dem Python-Code lesen, wollen Sie lieber als . –

+0

Was ist das Ergebnis nach dem Schreiben der gesamten MATLAB-Datei, wenn Sie diese Datei in Python öffnen und einen einfachen 'fid.read()' ausführen, um den gesamten Inhalt zu lesen? –

+0

Hilft das? http://stackoverflow.com/questions/874461/read-mat-files-in-python – cdarke

Antwort

1

Das Problem ist mit endianness, die Reihenfolge der Bits in einer Zahl.Sie müssen sich auf einem x86- oder x86-64-Computer befinden (da dies die einzigen sind, die MATLAB unterstützt), und das sind little-endian. Der Python >i teilt ihm jedoch mit, die Big-Endian-Byte-Reihenfolge zu verwenden. Sie verwenden also umgekehrte Byte-Anweisungen, wodurch die beiden Sprachen völlig unterschiedliche Zahlen auslesen.

Wenn Sie immer nur über die Verwendung des Python-Code auf einem x86 oder x86-64 Computer planen, oder Sie kümmern sich nur um Daten zwischen MATLAB und Python auf demselben Computer zu senden, dann können Sie die Bytereihenfolgemarkierung wegzulassen gerade komplett und verwende die native Byte-Reihenfolge (also i anstelle von >i). Wenn Sie auf einem PowerPC-System mit Python arbeiten, sollten Sie die Little-Endianess (<i) manuell angeben.

In diesem Beispiel scheint dies das einzige Problem zu sein. Ich möchte darauf hinweisen, dass, wenn Sie versuchen, Arrays/Matrizen von Daten eine Zeit zu lesen und zu schreiben, dann numpy.fromfile wird viel schneller und einfacher.

+0

Wenn Sie mit numpy arbeiten, benutzen Sie einfach np.loadtxt nicht. Nach Geschwindigkeit suchend wäre es np.fromfile> np.load> pd.read_csv >> np.loadtxt (basierend auf http://softwarerecs.stackexchange.com/questions/7463/fastest-python-library-to-read-a -csv-Datei). –

+0

Das Problem schien mit Endianness in Zusammenhang zu stehen. Ich dachte ursprünglich, es wäre in Ordnung, da MATLAB behauptet, dass das Angeben von 'fwrite (..., 'int')' bedeutet, daß 'int = 4 Bytes' ist. Nach dem Hinzufügen des 'ieee-be'-Formatierers schien es jedoch das Problem zu lösen. – Alex

+0

@Alex: warum willst du es Big-Endian? Da so ziemlich jeder Computer, den Sie heutzutage benutzen, entweder Little-Endian oder Dual-Endian ist, werden Sie unnötigen Overhead hinzufügen, indem Sie Ihre Daten zu Big-Endian machen. – TheBlackCat

1

Sie in Pandas Interessenten können hdf5 Speicher:.

In Python:

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]) 

in Matlab:

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

Aber Ich bin nicht sicher, ob es funktioniert, schrieb vollständig in Browser ...

+0

Ursprünglich verwendeten wir netcdf und wollten in unser eigenes binäres Dateiformat umwandeln, so dass es relativ sprachunabhängig wäre :(Leider muss ich Bleiben Sie bei dieser Reihe von Richtlinien. Mein Fehler, ich hätte das in der ursprünglichen Beschreibung setzen. – Alex

+0

Wie wäre es mit C++ machen? Wie zu schreiben Daten in c und dann speichern Sie es, lesen Sie es mit c, put Irgendwo ele? C ist universal Ich denke ... Ich habe nicht mit diesem Thema gespielt, aber ich würde von c dafür beginnen :) Am einfachsten wäre es, einfache csv-Dateien zu verwenden ... Am effizientesten in Speicher Cap wäre mit Pandas hdf5 Speichern mit Kompression ... Am effizientesten in Geschwindigkeit Ich weiß xD ... –

+0

Ja .. Ich denke, ich könnte mir nur die Mühe ersparen und fangen an, es in C zu schreiben. Danke für alles! – Alex

Verwandte Themen