2017-01-24 2 views
0

A eine Datei, die Fortran Verwendung gelesen werden können, und die folgende Ausgabe erzeugt:Fortran Binärdaten mit Python Lesen, schwimmt und ints

0  2044150  229424   0   0   0 
0.0000000000000000  0.0000000000000000  
2.97821895219385624E-003 0.0000000000000000  0.0000000000000000   
0.0000000000000000  7.81250000000000000E-003 127.00000000000000    0   0   0 91948296 10067568  7115688   0 
0   0   48 67.769999999999996  
0.30700001120567322  0.69300001859664917  0.67769998311996460 

Grundsätzlich einigen int * 4 Werte und etwas float * 8 Werte (im Header). Ich möchte in der Lage sein, diese Datei in Python zu lesen. Ich habe den folgenden Code:

f = open(fname,'rb') 
data = np.fromfile(file=f,dtype=np.int32) 
print data 

und ich bekomme das Ergebnis:

[  256   0 2044150  229424   0   0 
     0   0   0   0   0 536870912 
1063806407   0   0   0   0   0 
     0   0 ] 

Einige der Zahlen in Ordnung sind, und ich glaube, dass die 256 auf die Datensatzgröße bezieht. Allerdings, wenn ich versuche, in den Schwimmern zu lesen (von np.int32 Wechsel zu np.float64) bekomme ich

[ 1.26480805e-321 4.86836763e-309 0.00000000e+000 0.00000000e+000 
    0.00000000e+000 1.49166815e-154 5.25590200e-315  0.00000000e+000 
    0.00000000e+000 0.00000000e+000 5.26354425e-315 5.33599245e-315 
    0.00000000e+000 9.12063001e-306 3.51561699e-317 0.00000000e+000 
    -1.02951130e-086 2.68156223e+154 2.68156222e+154 -2.68156222e+154] 

die eindeutig falsch nicht nur für die int32s ist, sondern auch für den Schwimmer 64s Ich hatte versucht, zu lesen.

Ich dachte, das hätte vielleicht etwas mit big/lindendian zu tun, aber habe keine Lösung gefunden. Ich bin mir auch sicher, dass ich versuche, den richtigen Datentyp (float64) einzulesen und viele andere versucht habe und sie ähnliche (oder schlechtere) Ergebnisse produzieren.

Ich weiß, dass das Format der Kopfzeile ist int * 4 (6), real * 8 (6), real * 8, real * 8, int * 4, int * 4, int * 4 (6) , int * 4, int * 4, real * 8, real * 8, real * 8, real * 8, zeichen (96)

+3

Sie können eine Datei im gemischten Format nicht lesen, indem Sie entweder int oder float angeben. Du musst auswählen. Vielleicht könntest du es mit 'struct.unpack' versuchen –

+0

Mit vorherigen Dateien habe ich sie zweimal geöffnet, einmal mit fromfile mit dtype = int, dann wieder die gleiche Datei geöffnet und aus datei mit dtype = float benutzt und das hat vorher gut funktioniert. Mein Grund für das Stellen der Frage ist, dass dies irgendwie unerklärlich anders schien. – Jack

+0

das Problem ist die Datei beginnt mit 7 4-Byte-Ganzzahlen (Zählen der Kopfzeile) Als ungerade Sie sind nicht richtig ausgerichtet, wenn Sie einfach das ganze als 8-Byte-Werte lesen. – agentp

Antwort

0

Ihre Datendatei fehlt Struktur. Sie sollten zuerst wissen, was in der Datei steht, und dann eine Lesestrategie wählen, sonst werden Sie Ziffern lesen, werden aber nicht wissen, was sie bedeuten. Wie Jean-François Fabre schreibt, loadtxt kann nicht mit Ihrer Situation umgehen, müssen Sie die Logik für die Datei selbst codieren. Sie können das Parsen der numerischen Teile Stück für Stück an loadtxt delegieren, zum Beispiel mit https://docs.python.org/2/library/stringio.html#module-StringIO

+0

Vielleicht haben Sie die Tatsache übersehen, dass die Daten binär sind? –

0

Am Ende habe ich die oben vorgeschlagene Methode struct.unpack verwendet. Mein Code sieht ungefähr so ​​aus:

def read_block(start,data_format,data): 

    p = start # Count block size 

    # Read record size 
    rf = 'i' 
    rs = struct.calcsize(rf) 
    record = struct.unpack(rf,data[p:p+rs]) 
    p += rs 

    bs = record[0] 
    body = list(struct.unpack(data_format,data[p:p+bs])) 
    p += bs 

    p += rs # Record size again 

    return body,p-start 


''' Read specific file architecture ''' 
''' Easily modified ''' 
def read_gadget(gdt_file): 

    p = 0 

    with open(gdt_file,'rb') as binary_file: 
     data = binary_file.read() 


    header_fmt = '=6i8d10i4d96s'  
    header,header_size = read_block(p,header_fmt,data) 
    npart = header[:6] 
    mpart = header[6:12] 
    npart_tot = sum(npart) 
    p += header_size 


    pos_fmt = str(3*npart_tot)+'f' 
    pos_list,pos_size = read_block(p,pos_fmt,data) 
    pos_arr = np.zeros((npart_tot,3)) 
    for i in range(3): 
     pos_arr[:,i] = np.array(pos_list)[i*npart_tot:(i+1)*npart_tot] 
    p += pos_size 


    vel_fmt = str(3*npart_tot)+'f' 
    vel_list,vel_size = read_block(p,vel_fmt,data) 
    vel_arr = np.zeros((npart_tot,3)) 
    for i in range(3): 
     vel_arr[:,i] = np.array(vel_list)[i*npart_tot:(i+1)*npart_tot] 
    p += vel_size 

    id_fmt = str(npart_tot)+'l' 
    id_list,id_size = read_block(p,id_fmt,data) 
    p += id_size 
    id_arr = np.array(id_list) 


    mass_arr = np.array([]) 
    for i in range(6): 
     if npart[i]==0: 
      pass 
     elif npart[i]!=0 and mpart[i]==0: 
      mass_fmt = str(npart[i])+'f' 
      mass_list,mass_size = read_block(p,mass_fmt,data) 
      p += mass_size 
      mass_arr = np.append(mass_arr,np.array(mass_list)) 
     elif npart[i]!=0 and mpart[i]!=0: 
      mass_list = npart[i]*[mpart[i]] 
      mass_arr = np.append(mass_arr,np.array(mass_list)) 


    return header,pos_arr,vel_arr,id_arr,mass_arr 
+0

Da Sie die Struktur kennen, können Sie einfach eine Folge von 'np.fromfile'-Aufrufen mit dem dritten Argument ausführen, um anzugeben, wie viele Elemente jedes Typs gelesen werden sollen. – agentp