2009-07-22 16 views
54

Estoy tratando de leer un archivo BMP en Python. Sé que los primeros dos bytes indican la firma BMP. Los siguientes 4 bytes son el tamaño del archivo. Cuando excecute:Lectura de enteros del archivo binario en Python

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

consigo

ValueError: invalid literal for int() with base 10: 'F#\x13'

Lo que quiero hacer es leer esos cuatro bytes como un entero ... Parece Python ellas es la lectura como caracteres y devolver una cadena, que no se puede convertir a un número entero. ¿Cómo puedo hacer esto correctamente?

+2

Si su objetivo es * utilizar * el mapa de bits en lugar de perder tiempo escribiendo su propia biblioteca BMP (no es que eso no suene divertido ...) puede usar PIL http://www.pythonware.com/ productos/pil/que posiblemente ya tengas instalados. Pruebe: importar imagen –

+4

Gracias Jared, pero quería leer el bmp manualmente solo para divertirme! :) –

Respuesta

88

El método read devuelve una secuencia de bytes como una cadena. Para convertir de una secuencia de bytes de cadena a datos binarios, use el módulo incorporado struct: http://docs.python.org/library/struct.html.

import struct 

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

Tenga en cuenta que unpack siempre devuelve una tupla, por lo struct.unpack('i', fin.read(4))[0] da el valor entero que usted está después.

que es mejor usar la cadena de formato '<i' (< es un modificador que indica ascendente hacia la izquierda de orden de bytes y el tamaño y la alineación estándar - el valor por defecto es usar el orden de bytes de la plataforma, el tamaño y la alineación). De acuerdo con la especificación de formato BMP, los bytes deben estar escritos en orden de bytes Intel/little-endian.

+18

En lugar de escribir 'i = struct.unpack (...) [0]' A menudo escribo 'i, = struct.unpack (...)' –

+0

@Otto ¿Hay alguna razón por la que prefiera una forma sobre la ¿otro? ¿Hay alguna diferencia lógica? – Caltor

+1

Me resulta muy sorprendente que no haya una función incorporada para leer enteros (o Shorts, etc.) desde un archivo en Python. No soy un experto en Java, pero creo que tiene funciones nativas como readUnsignedShort() para hacer esto. – Caltor

4

Mientras lee el archivo binario, es necesario descomprimirlo en un entero, a fin de utilizar el módulo struct para que

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

struct.unpack devuelve una tupla – luc

+0

@luc, gracias, fijo –

6

Excepto struct también se puede utilizar array módulo

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

Buen punto. Pero esta solución no es tan flexible como la del módulo struct, ya que todos los elementos leídos a través de values.read() deben ser enteros largos (no es conveniente leer un entero largo, un byte y luego un entero largo, con el módulo de matriz). – EOL

+0

Estoy de acuerdo. 'array' es una forma eficiente de leer un archivo binario pero no es muy flexible cuando tenemos que tratar con la estructura, como mencionaste correctamente. –

+1

array.read está en desuso en favor de array.fromfile desde 1.51 –

31

Un método alternativo que no hace uso de 'struct.unpack()' sería usar NumPy:

import numpy as np 

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

'dtype' representa el tipo de datos y puede ser int #, uint #, float #, complex # o un tipo definido por el usuario. Ver numpy.fromfile.

Personalmente prefiero usar NumPy para trabajar con matriz/matriz de datos, ya que es mucho más rápido que el uso de listas de Python.

+5

Se puede esquiar la apertura de archivo: 'a = np.fromfile ('file.bin', dtype = np.uint32)' – MathieuS

2

A partir de Python 3.2 y versiones posteriores, también se puede lograr esto usando el método from_bytes int orígenes:

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

Tenga en cuenta que esta función requiere que se especifique si el número está codificado en formato grande- o ascendente hacia la izquierda , por lo que tendrá que determinar el endian-ness para asegurarse de que funciona correctamente.

Cuestiones relacionadas