2009-07-22 82 views
54

Tôi đang cố gắng đọ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 excecute:Đọc các số nguyên từ tệp nhị phân trong Python

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

tôi nhận được

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

Những gì tôi muốn làm là đọc bốn byte là một số nguyên ... Có vẻ như Python được đọc chúng như nhân vật và trả về một chuỗi, mà 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 là điều đó không có vẻ thú vị ...), bạn có thể sử dụng PIL http://www.pythonware.com/ sản phẩm/pil/mà bạn có thể đã cài đặt. Thử: nhập hình ảnh –

+4

Cảm ơn Jared, nhưng tôi muốn đọc bmp bằng tay chỉ để vui chơi! :) –

Trả lời

88

Phương thức read trả về một chuỗi các byte dưới dạng chuỗi. Để chuyển đổi từ chuỗi byte thành dữ liệu nhị phân, hãy sử dụng mô-đun struct được 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 unpack luôn trả về một tuple, vì vậy struct.unpack('i', fin.read(4))[0] cung cấp cho các giá trị số nguyên mà bạn đang theo đuổi.

Bạn có thể sử dụng chuỗi định dạng '<i' (< là công cụ sửa đổi cho biết thứ tự byte nhỏ và 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 ghi bằng thứ tự byte Intel/nhỏ.

+18

Thay vì viết 'i = struct.unpack (...) [0]' Tôi thường viết 'i, = struct.unpack (...)' –

+0

@Otto Có lý do nào bạn thích một cách trên khác? Có sự khác biệt hợp lý nào không? – Caltor

+1

Tôi thấy rất ngạc nhiên khi không có hàm tích hợp để đọc các số nguyên (hoặc Quần short vv) từ một tệp bằng Python. Tôi không có chuyên gia Java nhưng tôi tin rằng nó có các hàm gốc như readUnsignedShort() để làm điều này. – Caltor

4

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

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

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

+0

@luc, cảm ơn, đã sửa –

6

Trừ struct bạn cũng có thể sử dụng array mô-đun

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

Điểm tốt. Nhưng giải pháp này không linh hoạt như mô-đun cấu trúc, vì tất cả các phần tử đọc qua các giá trị.read() phải là các số nguyên dài (không thuận tiện để đọ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). – EOL

+0

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

+1

array.read không được hỗ trợ bởi array.fromfile từ 1.51 –

31

Một phương pháp thay thế không sử dụng 'struct.unpack()' sẽ 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 một kiểu do người dùng định nghĩa. Xem numpy.fromfile.

Cá nhân 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 việc sử dụng danh sách Python.

+5

Mở tệp có thể được bỏ qua: 'a = np.fromfile ('file.bin', dtype = np.uint32)' – MathieuS

2

Tính đến Python 3.2+, bạn cũng có thể thực hiện điều này bằng cách sử dụng phương pháp from_bytes int mẹ đẻ:

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

Lưu ý rằng chức năng này đòi hỏi bạn phải xác định xem số được mã hóa dưới dạng big- hoặc ít về cuối nhỏ , vì vậy bạn sẽ phải xác định endian-ness để đảm bảo nó hoạt động chính xác.

Các vấn đề liên quan