2010-07-10 56 views
13

Tôi đang đọc trong tệp nhị phân (trong trường hợp này là jpg) và cần tìm một số giá trị trong tệp đó. Đối với những người quan tâm, tệp nhị phân là một jpg và tôi đang cố gắng chọn kích thước của nó bằng cách tìm kiếm cấu trúc nhị phân là detailed here.Python: Tìm kiếm/đọc dữ liệu nhị phân

Tôi cần tìm FFC0 trong dữ liệu nhị phân, bỏ qua một số byte và sau đó đọc 4 byte (điều này sẽ cho tôi kích thước hình ảnh).

Cách tốt để tìm kiếm giá trị trong dữ liệu nhị phân là gì? Có tương đương với 'tìm', hoặc một cái gì đó như tái?

+1

bạn đã bao giờ nhìn vào tưởng tượng chưa? IIRC cũng có một thư viện python cho nó. – txwikinger

+0

Tôi có, và nó hoạt động tuyệt vời, nhưng nó khá nặng cho việc tìm kiếm kích thước của tập tin. – Parand

+1

bạn nên sử dụng một mô-đun thích hợp cho một cái gì đó như thế này http://snippets.dzone.com/posts/show/1021 –

Trả lời

7

Bạn thực sự có thể tải tệp vào chuỗi và tìm chuỗi đó cho chuỗi byte 0xffc0 bằng phương pháp str.find(). Nó hoạt động cho bất kỳ chuỗi byte nào.

Mã để làm điều này phụ thuộc vào một vài điều. Nếu bạn mở tệp ở chế độ nhị phân và bạn đang sử dụng Python 3 (cả hai có thể là cách thực hành tốt nhất cho kịch bản này), bạn sẽ cần phải tìm chuỗi byte (trái với chuỗi ký tự), có nghĩa là bạn phải thêm tiền tố vào chuỗi với b.

with open(filename, 'rb') as f: 
    s = f.read() 
s.find(b'\xff\xc0') 

Nếu bạn mở tập tin trong chế độ văn bản bằng Python 3, bạn sẽ phải tìm kiếm một chuỗi ký tự:

with open(filename, 'r') as f: 
    s = f.read() 
s.find('\xff\xc0') 

mặc dù không có lý do cụ thể để làm điều này. Nó không giúp bạn có được lợi thế so với cách trước và nếu bạn đang sử dụng nền tảng xử lý tệp nhị phân và tệp văn bản khác nhau (ví dụ: Windows), có khả năng điều này sẽ gây ra sự cố.

Python 2 không phân biệt giữa chuỗi byte và chuỗi ký tự, vì vậy nếu bạn đang sử dụng phiên bản đó, bạn không bao gồm hoặc loại trừ b trong b'\xff\xc0'. Và nếu nền tảng của bạn xử lý tệp nhị phân và tệp văn bản giống hệt nhau (ví dụ: Mac hoặc Linux), bạn cũng không cần phải sử dụng 'r' hoặc 'rb' làm chế độ tệp hay không. Nhưng tôi vẫn khuyên bạn nên sử dụng một cái gì đó giống như mẫu mã đầu tiên ở trên chỉ để tương thích về phía trước - trong trường hợp bạn đã từng chuyển sang Python 3, thì đó là một điều ít khắc phục hơn.

+6

Nếu đó là một tập tin thực sự lớn, nó không phải là một ý tưởng tốt để đọc nó vào một chuỗi tất cả cùng một lúc. – icktoofay

+2

Tôi nghi ngờ nó quá lớn, nó sẽ là một vấn đề. –

+3

Vì tôi chỉ tìm kiếm khung hình đầu tiên, tôi có thể đọc một phần nhỏ của tệp và quá trình thay vì đọc toàn bộ tệp. – Parand

4

Các re mô-đun không làm việc với cả hai chuỗi và nhị phân dữ liệu (str bằng Python 2 và bytes bằng Python 3), do đó bạn có thể sử dụng nó cũng như str.find cho nhiệm vụ của mình.

2

Vâng, rõ ràng là có PIL Mô-đun hình ảnh có kích thước làm thuộc tính. Nếu bạn muốn có được kích thước chính xác như thế nào bạn đề nghị và không tải các tập tin bạn sẽ phải đi qua nó từng dòng. Không phải là cách tốt nhất để làm điều đó nhưng nó sẽ làm việc.

6

Mô-đun bitstring được thiết kế cho mục đích này khá nhiều. Đối với trường hợp của bạn đoạn mã sau (mà tôi đã không kiểm tra) sẽ giúp minh họa:

from bitstring import ConstBitStream 
# Can initialise from files, bytes, etc. 
s = ConstBitStream(filename='your_file') 
# Search to Start of Frame 0 code on byte boundary 
found = s.find('0xffc0', bytealigned=True) 
if found: 
    print("Found start code at byte offset %d." % found[0]) 
    s0f0, length, bitdepth, height, width = s.readlist('hex:16, uint:16, 
                 uint:8, 2*uint:16') 
    print("Width %d, Height %d" % (width, height)) 
+0

Vì vậy, 'Bits.find' chỉ trả về một boolean và đặt thuộc tính' Bits.bytepos'? Có lẽ trong tài liệu mô-đun, bạn nên cảnh báo rằng 'bitstring' không phải là thread-safe (không phải là nó quan trọng trong câu trả lời này, tất nhiên). – tzot

+0

@ ΤΖΩΤΖΙΟΥ: Có, bạn có một điểm tốt. Tôi không thấy nó ngạc nhiên khi các phương thức đột biến hoặc các phương thức đọc không phải là chủ đề an toàn, nhưng việc sử dụng 'tìm' trên một đối tượng bất biến khôn ngoan có thể được mong đợi một cách hợp lý. Thành thật mà nói, nó không bao giờ bị cắt xén trước đây, nhưng nó là một cái gì đó để suy nghĩ về ... –

+0

Chỉ cần một ý tưởng: 'find' có thể trả về một đối tượng với tất cả các thông tin cần thiết, à la' re.match' và 're.search'. Bạn có thể có lớp "BitMatch" này là một lớp con của 'bool', cho khả năng tương thích ngược. – tzot

1

Thay vì đọc toàn bộ tập tin vào bộ nhớ, tìm kiếm nó và sau đó viết một tập tin mới ra đĩa bạn có thể sử dụng mmap mô-đun cho việc này. mmap sẽ không lưu toàn bộ tệp vào bộ nhớ và nó cho phép sửa đổi tại chỗ.

#!/usr/bin/python 

import mmap 

with open("hugefile", "rw+b") as f: 
    mm = mmap.mmap(f.fileno(), 0) 
    print mm.find('\x00\x09\x03\x03') 
0

python> = 3,2

import re 

f = open("filename.jpg", "rb") 
byte = f.read() 
f.close() 

matchObj = re.match(b'\xff\xd8.*\xff\xc0...(..)(..).*\xff\xd9', byte, re.MULTILINE|re.DOTALL) 
if matchObj: 
    # http://stackoverflow.com/questions/444591/convert-a-string-of-bytes-into-an-int-python 
    print (int.from_bytes(matchObj.group(1), 'big')) # height 
    print (int.from_bytes(matchObj.group(2), 'big')) # width 
1

Phương pháp find() nên chỉ được sử dụng nếu bạn cần phải biết vị trí của sub, nếu không, bạn có thể sử dụng toán tử in, ví dụ:

with open("foo.bin", 'rb') as f: 
    if b'\x00' in f.read(): 
     print('The file is binary!') 
    else: 
     print('The file is not binary!') 
+1

Điều này đã làm nó cho tôi - Tôi đã cố gắng để so sánh một chuỗi với một chuỗi byte. Tất cả những gì tôi phải làm là đặt b vào trước cụm từ tìm kiếm của tôi và nó được tìm thấy trong chuỗi byte. – pa1983

0

Trong Python 3.x bạn có thể tìm kiếm chuỗi byte bằng một chuỗi byte khác như sau:

>>> byte_array = b'this is a byte array\r\n\r\nXYZ\x80\x04\x95 \x00\x00\x00\x00\x00' 
>>> byte_array.find('\r\n\r\n'.encode()) 
20 
>>> 
Các vấn đề liên quan