2012-01-03 16 views
60

Szczególnie trudno jest znaleźć plik binarny w Pythonie. Czy może Pan mi pomóc? muszę przeczytać ten plik, który w Fortran 90 jest łatwo odczytywane przezCzytanie pliku binarnego z pythonem

int*4 n_particles, n_groups 
real*4 group_id(n_particles) 
read (*) n_particles, n_groups 
read (*) (group_id(j),j=1,n_particles) 

szczegółowo, format pliku jest:

Bytes 1-4 -- The integer 8. 
Bytes 5-8 -- The number of particles, N. 
Bytes 9-12 -- The number of groups. 
Bytes 13-16 -- The integer 8. 
Bytes 17-20 -- The integer 4*N. 
Next many bytes -- The group ID numbers for all the particles. 
Last 4 bytes -- The integer 4*N. 

Jak można przeczytać w Pythonie? Próbowałem wszystkiego, ale nigdy nie działało. Czy jest jakaś szansa, że ​​mógłbym użyć programu f90 w pythonie, czytając ten plik binarny, a następnie zapisać dane, których potrzebuję użyć?

+1

Czy ten plik napisany przez Fortran programie? Jeśli tak, to w jaki sposób został napisany, ponieważ Fortran domyślnie dodaje dodatkowe dane przed każdym rekordem, który zapisuje do pliku. Podczas czytania danych może być konieczne zachowanie ostrożności. – Chris

+1

Proszę zignorować mój poprzedni komentarz, intergers 8 i 4 * N to wyraźnie te dodatkowe dane. – Chris

+2

Zobacz także odpowiedzi na pytanie [czytanie pliku binarnego w pythonie] (http://stackoverflow.com/questions/1035340/reading-binary-file-in-python). – Chris

Odpowiedz

79

Czytaj binarną zawartość pliku tak:

with open(fileName, mode='rb') as file: # b is important -> binary 
    fileContent = file.read() 

następnie "rozpakować" danych binarnych za pomocą struct.unpack:

Bajty początkowe: struct.unpack("iiiii", fileContent[:20])

Korpus: ignore bajty nagłówkiem a końcowy bajt (= 24); Pozostała część tworzy ciało, aby poznać liczbę bajtów w ciele, wykonaj dzielenie całkowite przez 4; Uzyskany iloraz jest mnożony przez ciąg 'i' stworzyć poprawny format dla metody rozpakować:

struct.unpack("i" * ((len(fileContent) -24) // 4), fileContent[20:-4]) 

Bajt końcowy: struct.unpack("i", fileContent[-4:])

+0

Wielkie dzięki, ale z twoim kodem mogę odczytać początkowe i końcowe bajty, ale nie ciało. Otrzymuję ten komunikat o błędzie TypeError: nieobsługiwane typy argumentów dla //: 'str' i 'int'. Czy możesz mi lepiej wytłumaczyć znaczenie twojego kodu podczas czytania treści mojego pliku? – Brian

+0

Brakowało nawiasów. Zaktualizowałem swój post – gecco

+0

, który wymyśliłem sam! Wielkie dzięki za bardzo pomocną odpowiedź! – Brian

21

Ogólnie rzecz biorąc, polecam, aby zaglądać do tego modułu Pythona struct. Jest to standard w Pythonie i powinno być łatwe przetłumaczenie specyfikacji twojego pytania na ciąg formatujący odpowiedni dla struct.unpack().

Należy zauważyć, że jeśli istnieje "niewidzialne" wypełnienie pomiędzy polami/wokół nich, należy je znaleźć i dołączyć do połączenia unpack() lub odczytać nieprawidłowe bity.

Odczyt zawartości pliku, aby mieć coś do rozpakowania jest dość banalna:

import struct 

data = open("from_fortran.bin", "rb").read() 

(eight, N) = struct.unpack("@II", data) 

ten rozpakowuje pierwsze dwa pola, zakładając, że zaczną na samym początku pliku (bez wyściółki lub obcy dane), a także przy założeniu natywnej kolejności bajtów (symbol @). I s w ciągu formatowania oznacza "unsigned integer, 32 bits".

+0

ok, ale nie wiem nawet, jak odczytać bajty pliku. Z mojego pytania, jak mogę odczytać plik z bajtów od 5 do 8, a następnie przekonwertować wynik na liczbę całkowitą? Przepraszam, ale jestem nowy w Pythonie. – Brian

8

Można użyć numpy.fromfile, która może odczytywać dane zarówno z plików tekstowych, jak i binarnych. Najpierw skonstruuj typ danych, który reprezentuje format pliku, używając numpy.dtype, a następnie odczytaj ten typ z pliku, używając numpy.fromfile.

+0

Łatwo tego przegapić! Dokumenty są trochę cienkie; zobacz https://www.reddit.com/r/Python/comments/19q8nt/psa_consider_using_numpy_if_you_need_to_parse_a/ dla jakiejś dyskusji – lost

-1
import pickle 
f=open("filename.dat","rb") 
try: 
    while True: 
     x=pickle.load(f) 
     print x 
except EOFError: 
    pass 
f.close() 
+5

Prawdopodobnie warte tylko trochę wyjaśnienia, dlaczego jest to lepsze niż (lub przynajmniej tak dobre, jak) inne odpowiedzi. – Phil

+1

Czy przetestowałeś zweryfikowany działający z binarnym wygenerowanym fortranem? – agentp

+0

A także wyjaśnić, co robi ... Co to jest marynata? Co się ładuje 'pickle.load'? Czy ładuje strumień Fortran, pliki bezpośrednie lub sekwencyjne? Są różne i nie są kompatybilne. –