2016-04-01 16 views
0

Ich habe mit C geschrieben eine Datei im Binärformat geschrieben. Das Format ich verwendet habe, ist die folgende:Lese Binärdaten mit Header von C in Python

einen Header mit 5 Doppel (insgesamt 40 Bytes):

fwrite(&FirstNum, sizeof(double), 1, outFile); 
fwrite(&SecNum, sizeof(double), 1, outFile); 
fwrite(&ThirdNum, sizeof(double), 1, outFile); 
fwrite(&FourthNum, sizeof(double), 1, outFile);   
fwrite(&FifthNum, sizeof(double), 1, outFile); 

Und dann durchgeführt I A für cicle über 256^3 "Teilchen". Für jedes Teilchen schreiben I 9 Werte: die erste ist eine ganze Zahl und die andere 8 Doppel-, auf folgende Weise:

Ntot = 256*256*256 
for(i=0; i<Ntot; i++) 
    { 
    fwrite(&gp[i].GID, sizeof(int), 1, outFile); 

    /*----- Positions -----*/ 
    pos_aux[X] = gp[i].pos[X]; 
    pos_aux[Y] = gp[i].pos[Y]; 
    pos_aux[Z] = gp[i].pos[Z]; 

    fwrite(&pos_aux[0], sizeof(double), 3, outFile); //Positions in 3D 
    fwrite(&gp[i].DenConCell, sizeof(double), 1, outFile); //Density 
    fwrite(&gp[i].poten_r[0], sizeof(double), 1, outFile); //Field 1 
    fwrite(&gp[i].potDot_r[0], sizeof(double), 1, outFile); //Field 2 
    fwrite(&gp[i].potDot_app1[0], sizeof(double), 1, outFile); //Field 3 
    fwrite(&gp[i].potDot_app2[0], sizeof(double), 1, outFile); //Field 4 
    } 

gp Wo nur eine Datenstruktur ist, die Informationen meiner Teilchen enthält. Dann habe ich für jedes der 256^3 Partikel insgesamt 68 Bytes benutzt: 4 Bytes für das int + 8 * (8 Bytes) für die Doubles.

Was ich brauche ist ein solches Format zu lesen, aber in Python, um einige Plots zu machen, aber ich bin ein wenig neu mit Python. Ich habe einige der Antworten gelesen, um Dateien im Binärformat mit Python zu lesen, aber ich konnte nur meine Kopfzeile lesen, nicht den "Körper" oder den Rest der Informationen bezüglich der Partikel. Was ich habe versucht, ist die folgende:

Npart = 256 
with open("./path/to/my/binary/file.bin", 'rb') as bdata: 
    header_size = 40 # in bytes   
    bheader = bdata.read(40) 
    header_data = struct.unpack('ddddd', bheader) 
    FirstNum = header_data[0] 
    SecNum = header_data[1] 
    ThirdNum = header_data[2] 
    FourthNum = header_data[3] 
    FifthNum = header_data[4] 
    #Until here, if I print each number, I obtain the correct values. 
    #From here, is what I've tried in order to read the 9 data of the 
    #particles 
    bytes_per_part = 68 
    body_size = int((Npart**3) * bytes_per_part) 
    body_data_read = bdata.read(body_size) 
    #body_data = struct.unpack_from('idddddddd', bdata, offset=40) 
    #body_data = struct.unpack('=i 8d', body_data_read) 
    body_data = struct.unpack('<i 8d', body_data_read) 

    #+++++ Unpacking data ++++++ 
    ID_us = body_data[0] 
    pos_x_us = body_data[1] 
    pos_y_us = body_data[2] 
    pos_z_us = body_data[3] 
    DenCon_us = body_data[4] 

Aber wenn ich meinen Code ausführen, ich diesen Fehler erhalten:

body_data = struct.unpack('<i 8d', body_data_read) 
struct.error: unpack requires a string argument of length 68 

ich mit der ersten kommentierte Linie versucht:

#body_data = struct.unpack_from('idddddddd', bdata, offset=40) 

Aber der Fehler sagt:

struct.error: unpack requires a string argument of length 72 

Wenn ich die Linie

body_data = struct.unpack('=i 8d', body_data_read) 

oder die Linie

body_data = struct.unpack('<i 8d', body_data_read) 

ich den Fehler erhalten verwende ich zuerst zeigte:

struct.error: unpack requires a string argument of length 68 

der Tat, ich fühle mich wie ich überhaupt nicht verstehen, die Zeichenketten "=" und "<", weil ich mit ihnen die angenommene Länge erhalte, die ich lesen muss, aber ich kann nicht lesen. Was ich schließlich brauche, ist ein Array namens pos_x_us mit allen Positionen in x, in pos_y_us die Positionen in y, in pos_z_us die Positionen in z und so weiter für die anderen Werte. Ich werde mich bedanken, wenn Sie mir ein paar Ideen oder Erleuchtung darüber geben können, wie ich erreichen kann, was ich brauche.

+1

Ist 'struct.unpack_from ('=' + (Npart ** 3) * 'i8d', body_data_read)' Arbeit? Es sollte alle Daten auf einmal lesen, nach denen Sie sie alle 9 Werte teilen können – Reti43

+0

Danke von Ihrer Antwort. Es sieht aus wie Werke, ich habe nicht den gleichen Fehler, aber wenn ich versuche, sie so zu teilen, wie ich es mit 'pos_x_us = body_data [1] gezeigt habe, gibt es nur eine Zahl, nicht das komplette Array zu pos_x_us. Wie kann ich es tun? – Darivadi

+0

Ja, 'body_data [1]' holt nur den Wert an der zweiten Position in der Liste. Wenn Sie alle x Werte haben möchten, verwenden Sie Slicing: 'body_data [1 :: 9]'. – Reti43

Antwort

1

Ihr Problem trat auf, weil die Puffergröße nicht dem Format entsprach. Versuchen wir es mit einigen zufälligen Daten. 12 Bytes insgesamt, bestimmt für einen int und einen float.

>>> data = '\xf4\x9f\x97\xcd\xf2\xbe\xd6\x87\x18\xe3\x17\xdf' 

Wenn Sie nicht verwenden '<', '>', '=' und '!', Wird es padding sein.

Padding is only automatically added between successive structure members. No padding is added at the beginning or the end of the encoded struct.

>>> struct.unpack('id', data) 

Traceback (most recent call last): 
    File "<pyshell#56>", line 1, in <module> 
    struct.unpack('id', data) 
error: unpack requires a string argument of length 16 

Aber

>>> struct.unpack('=id', data) 
(-845701132, -1.2217466572589222e+150) 

Um genauer zu sein, 'd' dauert 8 Bytes auf seiner eigenen und 'i' nimmt 4.'iii' ist in Ordnung, da es sich um den gleichen Typ handelt. Aber wenn Sie versuchen, 'id' zu tun, wird es das nicht mögen und es wird die ganze Zahl auf 8 Bytes auffüllen. Sie können das gleiche mit 'c' sehen, das 1 Byte aufnimmt, aber 'ci', das 8 erfordert. Im Grunde funktionierte struct.unpack('ddddd') wegen der Umstände gut.

Ihr anderer Fehler kommt von dem Format, das nicht mit der Größe des Puffers übereinstimmt. Wenn Sie struct.unpack() verwenden, muss es genau übereinstimmen, aber wenn Sie struct.unpack_from() verwenden, müssen Sie mindestens die Größe des Formats haben. Versuchen wir es mit 24 Datenbytes.

# this will fetch 12 bytes, even if the stream has more 
>>> struct.unpack_from('=id', 2*data) 
(-845701132, -1.2217466572589222e+150) 

Aber

>>> struct.unpack('=id', 2*data) 

Traceback (most recent call last): 
    File "<pyshell#60>", line 1, in <module> 
    struct.unpack('=id', 2*data) 
error: unpack requires a string argument of length 12 

Wie Sie jetzt sehen können, Ihre Daten tatsächlich war

body_size = int((Npart**3) * bytes_per_part) 
body_data_read = bdata.read(body_size) 

Um das zu passen, benötigt man ein Format von 'i8di8di8d ...' Npart **dreimal. So,

Jetzt haben Sie alle Daten auf einmal eingelesen und Sie können sie aufteilen, wie Sie es wünschen. Zum Beispiel hat der zweite Wert die x-Koordinate des ersten Partikels und da dieses Muster alle 9 Werte wiederholt, können Sie die x-Koordinaten aller Partikel mit Slicing erhalten.

pos_x_us = body_data[1::9] 
+0

Vielen Dank nochmal! Sie waren sehr klar und hilfreich. Es hat perfekt funktioniert. – Darivadi