92 votes

Lecture d'entiers à partir d'un fichier binaire en Python

J'essaie de lire un BMP en Python. Je sais que les deux premiers octets indiquent le cabinet BMP. Les 4 octets suivants sont la taille du fichier. Lorsque j'exécute :

fin = open("hi.bmp", "rb")
firm = fin.read(2)  
file_size = int(fin.read(4))  

J'ai compris :

ValueError : littéral invalide pour int() avec base 10 : 'F# \x13 '

Ce que je veux faire, c'est lire ces quatre octets en tant qu'entier, mais il semble que Python les lise en tant que caractères et renvoie une chaîne de caractères, qui ne peut pas être convertie en entier. Comment puis-je faire cela correctement ?

2 votes

Si votre objectif est de utiliser le bitmap au lieu de passer du temps à écrire votre propre bibliothèque BMP (non pas que cela n'ait pas l'air amusant...) vous pouvez utiliser PIL pythonware.com/produits/pil que vous avez peut-être déjà installé. Essayez : import Image

8 votes

Merci Jared, mais je voulais lire le bmp manuellement seulement pour m'amuser ! :)

133voto

codeape Points 38576

El read renvoie une séquence d'octets sous forme de chaîne. Pour convertir une séquence d'octets sous forme de chaîne en données binaires, utilisez la fonction intégrée struct module : http://docs.python.org/library/struct.html .

import struct

print(struct.unpack('i', fin.read(4)))

Notez que unpack renvoie toujours un tuple, donc struct.unpack('i', fin.read(4))[0] donne la valeur entière que vous recherchez.

Vous devriez probablement utiliser la chaîne de format '<i' (< est un modificateur qui indique un ordre d'octet little-endian et une taille et un alignement standard - la valeur par défaut est d'utiliser l'ordre d'octet, la taille et l'alignement de la plate-forme). Selon la spécification du format BMP, les octets doivent être écrits dans l'ordre des octets Intel/little-endian.

22 votes

Au lieu d'écrire i = struct.unpack(...)[0] J'écris souvent i, = struct.unpack(...)

0 votes

@Otto Y a-t-il une raison pour laquelle vous préférez une façon plutôt qu'une autre ? Y a-t-il une différence logique ?

4 votes

Je trouve très surprenant qu'il n'y ait pas de fonction intégrée pour lire des entiers (ou des shorts, etc.) à partir d'un fichier en Python. Je ne suis pas un expert de Java mais je crois qu'il existe des fonctions natives telles que readUnsignedShort() pour faire cela.

59voto

Emanuel Ey Points 564

Une méthode alternative qui ne fait pas appel à 'struct.unpack()' serait d'utiliser NumPy :

import numpy as np

f = open("file.bin", "r")
a = np.fromfile(f, dtype=np.uint32)

dtype' représente le type de données et peut être int#, uint#, float#, complex# ou un type défini par l'utilisateur. Voir numpy.fromfile .

Personnellement, je préfère utiliser NumPy pour travailler avec des tableaux/matrices car c'est beaucoup plus rapide que d'utiliser les listes Python.

15 votes

L'ouverture du fichier peut être ignorée : a = np.fromfile('file.bin', dtype=np.uint32)

27voto

CrepeGoat Points 893

À partir de Python 3.2+, vous pouvez également réaliser cette opération en utilisant la commande from_bytes méthode native int :

file_size = int.from_bytes(fin.read(2), byteorder='big')

Notez que cette fonction vous demande de spécifier si le nombre est codé au format big-endian ou little-endian, vous devrez donc déterminer le caractère endian pour vous assurer qu'elle fonctionne correctement.

0 votes

Ne devriez-vous pas lire 4 octets pour int ?

0 votes

Dans python3, int sont dimensionnés dynamiquement (il s'agit de la même implémentation que celle de Python2). long ; on parle aussi parfois de "gros int"), ce qui, je crois, est la motivation de l'ajout de cette fonction int en premier lieu. docs.python.org/3/library/ .

0 votes

Alors pourquoi 2 ? Comment le savez-vous ?

6voto

Nick Dandoulakis Points 26809

Sauf struct vous pouvez également utiliser array module

import array
values = array.array('l') # array of long integers
values.read(fin, 1) # read 1 integer
file_size  = values[0]

0 votes

C'est un bon point. Mais cette solution n'est pas aussi souple que celle du module struct, puisque tous les éléments lus par values.read() doivent être des entiers longs (il n'est pas pratique de lire un entier long, un octet, puis un entier long, avec le module array).

0 votes

Je suis d'accord. array est un moyen efficace de lire un fichier binaire mais n'est pas très flexible lorsqu'il s'agit de traiter la structure, comme vous l'avez correctement mentionné.

1 votes

Array.read est déprécié au profit de array.fromfile depuis la 1.51

4voto

Anurag Uniyal Points 31931

Comme vous lisez le fichier binaire, vous devez le décompresser en un entier, donc utiliser le module struct pour cela.

import struct
fin = open("hi.bmp", "rb")
firm = fin.read(2)  
file_size, = struct.unpack("i",fin.read(4))

0 votes

Struct.unpack retourne un tuple

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X