Đọc số nguyên từ tệp nhị phân bằng Python


82

Tôi đang cố đọc tệp BMP bằng Python. Tôi biết hai byte đầu tiên cho biết công ty BMP. 4 byte tiếp theo là kích thước tệp. Khi tôi thực hiện:

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

Tôi có:

ValueError: ký tự không hợp lệ cho int () với cơ số 10: 'F # \ x13'

Những gì tôi muốn làm là đọc bốn byte đó dưới dạng số nguyên, nhưng có vẻ như Python đang đọc chúng dưới dạng ký tự và trả về một chuỗi, không thể chuyển đổi thành số nguyên. Làm thế nào tôi có thể làm điều này một cách chính xác?


2
Nếu mục tiêu của bạn là sử dụng bitmap thay vì dành thời gian viết thư viện BMP của riêng bạn (không phải điều đó nghe có vẻ không thú vị ...), bạn có thể sử dụng PIL pythonware.com/products/pil mà bạn có thể đã cài đặt. Hãy thử: nhập khẩu Hình ảnh
Jared Updike

7
Cảm ơn Jared, nhưng tôi chỉ muốn đọc bmp theo cách thủ công để giải trí! :)
Manuel Araoz 22-07-09

Câu trả lời:


123

Các readphương thức trả về một chuỗi các byte như là một chuỗi. Để chuyển đổi từ chuỗi byte-chuỗi thành dữ liệu nhị phân, hãy sử dụng structmô-đun tích hợp sẵn: http://docs.python.org/library/struct.html .

import struct

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

Lưu ý rằng unpackluôn trả về một bộ giá trị, vì vậy hãy struct.unpack('i', fin.read(4))[0]cung cấp giá trị số nguyên mà bạn đang theo sau.

Bạn có thể nên sử dụng chuỗi định dạng '<i'(<là một bổ ngữ chỉ ra thứ tự byte nhỏ, kích thước chuẩn và căn chỉnh - mặc định là sử dụng thứ tự byte, kích thước và căn chỉnh của nền tảng). Theo thông số định dạng BMP, các byte phải được viết theo thứ tự byte Intel / little-endian.


22
Thay vì viết i = struct.unpack(...)[0]tôi thường ghii, = struct.unpack(...)
Otto Allmendinger

@Otto Có lý do nào bạn thích cách này hơn cách kia không? Có sự khác biệt logic nào không?
Caltor 16/10/12

2
Tôi thấy rất ngạc nhiên là không có một hàm tích hợp nào để đọc số nguyên (hoặc Shorts, v.v.) từ một tệp bằng Python. Tôi không phải là chuyên gia Java nhưng tôi tin rằng nó có các hàm gốc như readUnsignedShort () để làm việc này.
Caltor 16/10/12

@codeape Bạn có thể xác định [0] đang làm gì không hoặc ít nhất là loại thành phần ngôn ngữ nào. Nó không rõ ràng ngay lập tức và hầu như không thể tìm kiếm trong tài liệu Python.
Caltor 16/10/12

Đối với danh sách và bộ giá trị, obj [N] có nghĩa là: lấy phần tử thứ N của obj. Xem docs.python.org/tutorial/introduction.html#lists
codeape

50

Một phương pháp thay thế không sử dụng 'struct.unpack ()' sẽ là sử dụng NumPy :

import numpy as np

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

'dtype' đại diện cho kiểu dữ liệu và có thể là int #, uint #, float #, complex # hoặc kiểu do người dùng xác định. Thấy chưa numpy.fromfile.

Cá nhân tôi thích sử dụng NumPy để làm việc với dữ liệu mảng / ma trận vì nó nhanh hơn rất nhiều so với sử dụng danh sách Python.


13
Mở tập tin có thể được skiped:a = np.fromfile('file.bin', dtype=np.uint32)
Mathieu Schopfer

16

Kể từ Python 3.2+, bạn cũng có thể thực hiện điều này bằng cách sử dụng from_bytesphương thức int gốc:

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

Lưu ý rằng hàm này yêu cầu bạn chỉ định xem số được mã hóa ở định dạng big- hay little-endian, vì vậy bạn sẽ phải xác định endian-ness để đảm bảo nó hoạt động chính xác.


6

Ngoại trừ structbạn cũng có thể sử dụng arraymô-đun

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

Điểm tốt. Nhưng giải pháp này không linh hoạt như giải pháp của mô-đun struct, vì tất cả các phần tử được đọc qua giá trị .read () phải là số nguyên dài (không thuận tiện khi đọc một số nguyên dài, một byte và sau đó là một số nguyên dài, với mô-đun mảng).
Eric O Lebigot,

Tôi đồng ý. arraylà một cách hiệu quả để đọc tệp nhị phân nhưng không linh hoạt lắm khi chúng ta phải xử lý cấu trúc, như bạn đã đề cập chính xác.
Nick Dandoulakis

1
array.read được phản đối ủng hộ array.fromfile từ 1,51

4

Khi bạn đang đọc tệp nhị phân, bạn cần giải nén nó thành một số nguyên, vì vậy hãy sử dụng mô-đun struct cho việc đó

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

struct.unpack trả về một tuple
luc

1

Khi bạn đọc từ một tệp nhị phân, một kiểu dữ liệu được gọi là byte được sử dụng. Điều này hơi giống danh sách hoặc tuple, ngoại trừ nó chỉ có thể lưu trữ các số nguyên từ 0 đến 255.

Thử:

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]

Hoặc là:

file_size = list(fin.read(4))

Thay vì:

file_size = int(fin.read(4))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.