2012-01-03 22 views
60

Encuentro archivo binario lectura particularmente difícil con Python. ¿Puedes darme una mano? Necesito leer este archivo, que en Fortran 90 es fácilmente leído porLa lectura de un archivo binario con el pitón

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) 

En detalle, el formato de archivo es:

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. 

Como puedo leer esto con Python? Intenté todo, pero nunca funcionó. ¿Hay alguna posibilidad de que use un programa f90 en python, leyendo este archivo binario y luego guardando los datos que necesito usar?

+1

Fue este archivo escrito por un programa de Fortran? De ser así, cómo se escribió, ya que Fortran, de forma predeterminada, agrega datos adicionales antes de cada registro que escribe en el archivo. Es posible que deba tener cuidado con esto al leer los datos. – Chris

+1

Por favor, ignore mi comentario anterior, los intergers 8 y 4 * N son claramente estos datos adicionales. – Chris

+2

También, ver respuestas a la pregunta [leer archivo binario en Python] (http://stackoverflow.com/questions/1035340/reading-binary-file-in-python). – Chris

Respuesta

79

Leer el contenido del archivo binario de la siguiente manera:

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

luego "desempaquetar" datos binarios usando struct.unpack:

Los bytes de inicio: struct.unpack("iiiii", fileContent[:20])

El cuerpo: ignorar los bytes de encabezamiento y la octeto final (= 24); La parte restante forma el cuerpo, para saber el número de bytes en el cuerpo haga una división entera por 4; El cociente obtenido se multiplica por la cadena 'i' para crear el formato correcto para el método de desempaquetado:

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

El byte final: struct.unpack("i", fileContent[-4:])

+0

Muchas gracias, pero con su código puedo leer los bytes iniciales y finales, pero no el cuerpo. Aparece este mensaje de error TypeError: tipo (s) de operandos no soportados para //: 'str' e 'int'. ¿Me puede explicar mejor el significado de su código al leer el cuerpo de mi archivo? – Brian

+0

Algunos paréntesis faltaban. Actualicé mi publicación – gecco

+0

¡Me di cuenta por mi cuenta! ¡Muchas gracias por la respuesta tan útil! – Brian

21

En general, yo recomendaría que se mira en el uso del módulo de Python struct para esto. Es estándar con Python, y debe ser fácil de traducir las especificaciones de la pregunta en una cadena de formato adecuado para struct.unpack().

Tenga en cuenta que si hay relleno "invisible" entre los campos, tendrá que averiguarlo e incluirlo en la llamada unpack(), o leerá los bits incorrectos.

La lectura de los contenidos del archivo con el fin de tener algo para descomprimir es bastante trivial:

import struct 

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

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

Este desempaqueta los dos primeros campos, en el supuesto de que empiecen desde el principio del archivo (sin relleno o ajena datos), y también asumiendo el orden de bytes nativo (el símbolo @). El I s en la cadena de formato significa "entero sin signo, 32 bits".

+0

bien, pero ni siquiera sé cómo leer los bytes del archivo. De mi pregunta, ¿cómo puedo leer el archivo de los bytes 5 a 8 y luego convertir el resultado a un número entero? Lo siento, pero soy nuevo con Python. – Brian

8

Usted podría utilizar numpy.fromfile, que puede leer los datos de texto y archivos binarios. Se podría construir un primer tipo de datos, la cual representa el formato de archivo, utilizando numpy.dtype, y luego leer este tipo de archivo usando numpy.fromfile.

+0

¡Fácil de perder esto! Los documentos son un poco delgados; ver https://www.reddit.com/r/Python/comments/19q8nt/psa_consider_using_numpy_if_you_need_to_parse_a/ para más información – lost

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

Probablemente valga solo una pequeña explicación de por qué esto es mejor que (o al menos tan bueno) otras respuestas. – Phil

+1

has probado una verificada esto funciona con el binario fortran generado? – agentp

+0

Y también explica qué hace ... ¿Qué es pickle? ¿Qué carga 'pickle.load'? ¿Carga una secuencia de Fortran, archivos directos o secuenciales? Son diferentes y no compatibles. –

Cuestiones relacionadas