Estoy intentando leer un archivo BMP en Python. Sé que los dos primeros bytes indican la firma BMP. Los siguientes 4 bytes son el tamaño del archivo. Cuando ejecuto:
fin = open("hi.bmp", "rb")
firm = fin.read(2)
file_size = int(fin.read(4))
Yo obtengo:
ValueError: literal no válido para int () con base 10: 'F # \ x13'
Lo que quiero hacer es leer esos cuatro bytes como un número entero, pero parece que Python los está leyendo como caracteres y devuelve una cadena, que no se puede convertir en un número entero. ¿Cómo puedo hacer esto correctamente?
Respuestas:
El
read
método devuelve una secuencia de bytes como una cadena. Para convertir de una secuencia de bytes de cadena a datos binarios, use elstruct
módulo incorporado : 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 questruct.unpack('i', fin.read(4))[0]
proporciona el valor entero que busca.Probablemente debería usar la cadena de formato
'<i'
(<es un modificador que indica el orden de bytes little-endian y el tamaño y alineación estándar; el valor predeterminado es usar el orden de bytes, el tamaño y la alineación de la plataforma). Según la especificación del formato BMP, los bytes deben escribirse en orden de bytes Intel / little-endian.fuente
i = struct.unpack(...)[0]
, escribo a menudoi, = struct.unpack(...)
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 datos de matriz / matriz, ya que es mucho más rápido que usar listas de Python.
fuente
a = np.fromfile('file.bin', dtype=np.uint32)
A partir de Python 3.2+, también puede lograr esto usando el
from_bytes
método int nativo:file_size = int.from_bytes(fin.read(2), byteorder='big')
Tenga en cuenta que esta función requiere que especifique si el número está codificado en formato big- o little-endian, por lo que tendrá que determinar el endian-ness para asegurarse de que funciona correctamente.
fuente
Excepto
struct
que también puedes usar elarray
móduloimport array values = array.array('l') # array of long integers values.read(fin, 1) # read 1 integer file_size = values[0]
fuente
array
es una forma eficiente de leer un archivo binario pero no muy flexible cuando tenemos que lidiar con la estructura, como mencionaste correctamente.Mientras lee el archivo binario, debe descomprimirlo en un número entero, así que use el módulo struct para eso
import struct fin = open("hi.bmp", "rb") firm = fin.read(2) file_size, = struct.unpack("i",fin.read(4))
fuente
Cuando lee de un archivo binario, se usa un tipo de datos llamado bytes. Esto es un poco como una lista o una tupla, excepto que solo puede almacenar enteros de 0 a 255.
Tratar:
file_size = fin.read(4) file_size0 = file_size[0] file_size1 = file_size[1] file_size2 = file_size[2] file_size3 = file_size[3]
O:
file_size = list(fin.read(4))
En vez de:
file_size = int(fin.read(4))
fuente