web-dev-qa-db-fra.com

Lire un fichier binaire avec Python

Je trouve particulièrement difficile de lire un fichier binaire avec Python. Pouvez-vous me donner un coup de main? Je dois lire ce fichier qui, dans Fortran 90, est facilement lisible par

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 détail, le format de fichier est:

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. 

Comment puis-je lire ceci avec Python? J'ai tout essayé mais cela n'a jamais fonctionné. Existe-t-il une chance que je puisse utiliser un programme f90 en python pour lire ce fichier binaire, puis enregistrer les données que je dois utiliser?

70
Brian

Lisez le contenu du fichier binaire comme ceci:

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

puis "décompressez" les données binaires en utilisant struct.unpack :

Les octets de début: struct.unpack("iiiii", fileContent[:20])

Le corps: ignore les octets d'en-tête et l'octet final (= 24); La partie restante forme le corps, pour connaître le nombre d'octets dans le corps, faites une division entière par 4; Le quotient obtenu est multiplié par la chaîne 'i' pour créer le format correct pour la méthode de décompression:

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

L'octet final: struct.unpack("i", fileContent[-4:])

98
gecco

En général, je vous conseillerais d'utiliser le module struct de Python pour cela. Il est standard avec Python et il devrait être facile de traduire les spécifications de votre question en une chaîne de formatage adaptée à struct.unpack().

Notez que s'il y a un remplissage "invisible" entre/autour des champs, vous devrez le comprendre et l'inclure dans l'appel unpack(), sinon vous lirez les mauvais bits.

Lire le contenu du fichier pour avoir quelque chose à décompresser est assez trivial:

import struct

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

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

Cela décompresse les deux premiers champs, en supposant qu'ils commencent au tout début du fichier (pas de remplissage ni de données superflues), et en supposant également un ordre d'octet natif (le symbole @). La Is dans la chaîne de formatage signifie "entier non signé, 32 bits".

22
unwind

Vous pouvez utiliser numpy.fromfile , qui peut lire des données à partir de fichiers texte et binaires. Vous devez d'abord créer un type de données, qui représente votre format de fichier, à l'aide de numpy.dtype , puis lire ce type à partir d'un fichier à l'aide de numpy.fromfile.

10
Chris

Pour lire un fichier binaire dans un objet bytes:

from pathlib import Path
data = Path('/path/to/file').read_bytes()  # Python 3.5+

Pour créer un int à partir des octets 0 à 3 des données:

i = int.from_bytes(data[:4], byteorder='little', signed=False)

Pour décompresser plusieurs ints des données:

import struct
ints = struct.unpack('iiii', data[:16])
0
Eugene Yarmash