Próbuję odczytać plik BMP w Pythonie. Wiem, że pierwsze dwa bajty wskazują firmę BMP. Następne 4 bajty to rozmiar pliku. Kiedy wykonuję:
fin = open("hi.bmp", "rb")
firm = fin.read(2)
file_size = int(fin.read(4))
Dostaję:
ValueError: nieprawidłowy literał int () o podstawie 10: „F # \ x13”
Chcę odczytać te cztery bajty jako liczbę całkowitą, ale wygląda na to, że Python odczytuje je jako znaki i zwraca ciąg, którego nie można przekonwertować na liczbę całkowitą. Jak mogę to zrobić poprawnie?
Odpowiedzi:
read
Metoda zwraca sekwencję bajtów jako ciąg znaków. Aby przekonwertować ciąg bajtów na dane binarne, użyj wbudowanegostruct
modułu: http://docs.python.org/library/struct.html .import struct print(struct.unpack('i', fin.read(4)))
Zauważ, że
unpack
zawsze zwraca krotkę, więcstruct.unpack('i', fin.read(4))[0]
podaje wartość całkowitą, której szukasz.Prawdopodobnie powinieneś użyć łańcucha formatującego
'<i'
(<jest modyfikatorem, który wskazuje kolejność bajtów little-endian oraz standardowy rozmiar i wyrównanie - domyślnie jest używana kolejność bajtów, rozmiar i wyrównanie platformy). Zgodnie ze specyfikacją formatu BMP, bajty powinny być zapisane w kolejności bajtów Intel / little-endian.źródło
i = struct.unpack(...)[0]
, często piszęi, = struct.unpack(...)
Alternatywną metodą, która nie korzysta z funkcji „struct.unpack ()”, byłoby użycie NumPy :
import numpy as np f = open("file.bin", "r") a = np.fromfile(f, dtype=np.uint32)
„dtype” reprezentuje typ danych i może być typu int #, uint #, float #, complex # lub typu zdefiniowanego przez użytkownika. Zobacz
numpy.fromfile
.Osobiście wolę używać NumPy do pracy z danymi tablicowymi / macierzowymi, ponieważ jest to o wiele szybsze niż korzystanie z list Pythona.
źródło
a = np.fromfile('file.bin', dtype=np.uint32)
Od wersji Python 3.2+ możesz to również osiągnąć przy użyciu
from_bytes
natywnej metody int:file_size = int.from_bytes(fin.read(2), byteorder='big')
Zwróć uwagę, że ta funkcja wymaga określenia, czy liczba jest zakodowana w formacie big- czy little-endian, więc będziesz musiał określić endian-ness, aby upewnić się, że działa poprawnie.
źródło
Oprócz tego
struct
możesz również użyćarray
moduleimport array values = array.array('l') # array of long integers values.read(fin, 1) # read 1 integer file_size = values[0]
źródło
array
jest skutecznym sposobem odczytu pliku binarnego, ale niezbyt elastycznym, gdy mamy do czynienia ze strukturą, jak słusznie wspomniałeś.Gdy czytasz plik binarny, musisz rozpakować go na liczbę całkowitą, więc użyj do tego modułu struct
import struct fin = open("hi.bmp", "rb") firm = fin.read(2) file_size, = struct.unpack("i",fin.read(4))
źródło
Podczas odczytu z pliku binarnego używany jest typ danych zwany bajtami. Przypomina to trochę listę lub krotkę, z wyjątkiem tego, że może przechowywać tylko liczby całkowite od 0 do 255.
Próbować:
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]
Lub:
file_size = list(fin.read(4))
Zamiast:
file_size = int(fin.read(4))
źródło