Поиск / чтение двоичных данных в Python - PullRequest
22 голосов
/ 10 июля 2010

Я читаю в двоичном файле (в данном случае jpg), и мне нужно найти некоторые значения в этом файле.Для тех, кто заинтересован, бинарный файл является jpg, и я пытаюсь определить его размеры, ища бинарную структуру как подробно здесь .

Мне нужно найти FFC0 в двоичных данных, пропустить некоторое количество байтов, а затем прочитать 4 байта (это должно дать мне размеры изображения).

Какой хороший способ поискадля значения в двоичных данных?Есть ли эквивалент 'find' или что-то вроде re?

Ответы [ 8 ]

12 голосов
/ 10 июля 2010

Вы можете загрузить файл в строку и найти в этой строке последовательность байтов 0xffc0, используя метод str.find().Это работает для любой последовательности байтов.

Код для этого зависит от нескольких вещей.Если вы открываете файл в двоичном режиме и используете Python 3 (оба из которых, вероятно, являются лучшими для этого сценария), вам нужно искать строку байтов (в отличие от строки символов), что означает, что вынеобходимо префикс строки с b.

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

Если вы откроете файл в текстовом режиме в Python 3, вам придется искать строку символов:

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

хотя для этого нет особой причины.Это не дает вам никаких преимуществ по сравнению с предыдущим способом, и если вы работаете на платформе, которая обрабатывает двоичные и текстовые файлы по-разному (например, Windows), есть вероятность, что это вызовет проблемы.

Python2 не делает различий между байтовыми строками и символьными строками, поэтому, если вы используете эту версию, не имеет значения, включаете ли вы или исключаете b в b'\xff\xc0'.И если ваша платформа обрабатывает двоичные файлы и текстовые файлы одинаково (например, Mac или Linux), не имеет значения, используете ли вы 'r' или 'rb' в качестве файлового режима.Но я бы по-прежнему рекомендовал использовать что-то вроде первого примера кода, приведенного выше, только для прямой совместимости - в случае, если вы когда-нибудь переключитесь на Python 3, исправить это будет на одну вещь меньше.

6 голосов
/ 10 июля 2010

Модуль bitstring был разработан для этой цели. Для вашего случая должен помочь следующий код (который я не тестировал):

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))
5 голосов
/ 18 февраля 2014

Вместо того, чтобы читать весь файл в память, искать его и затем записывать новый файл на диск, вы можете использовать для этого модуль mmap.mmap не сохранит весь файл в памяти и позволяет модифицировать его на месте.

#!/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')
4 голосов
/ 10 июля 2010

Модуль re работает как со строковыми , так и с двоичными данными (str в Python 2 и bytes в Python 3), поэтому вы можете использовать его как а также str.find для вашей задачи.

2 голосов
/ 10 июля 2010

Ну, очевидно, есть PIL Модуль Image имеет размер в качестве атрибута. Если вы хотите получить размер в точности так, как вы предлагаете, и без загрузки файла вам придется проходить его построчно. Не самый хороший способ сделать это, но это сработало бы.

1 голос
/ 27 февраля 2016

В Python 3.x вы можете искать байтовую строку по другой байтовой строке, например:

>>> 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
>>>
1 голос
/ 01 июня 2015

Метод find() следует использовать только в том случае, если вам нужно знать положение sub, если нет, вы можете использовать оператор in, например:

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!')
0 голосов
/ 17 мая 2014

Для 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:
    # /271022/kak-preobrazovat-stroku-baitov-v-int-v-python
    print (int.from_bytes(matchObj.group(1), 'big')) # height
    print (int.from_bytes(matchObj.group(2), 'big')) # width
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...