>LL — это строка формата, которая указывает функции unpack(), как интерпретировать входные последовательности байтов и преобразовать их в типы данных Python. Рассмотрим ее детальнее:
• символ < означает, что целые числа хранятся в формате
• каждый символ L определяет четырехбайтное целое число типа unsigned long.
Вы можете проверить значение каждого четырехбайтного набора непосредственно:
>>> data[16:20]
b'\x00\x00\x00\x9a'
>>> data[20:24]0x9a
b'\x00\x00\x00\x8d'
У целых чисел с обратным порядком байтов главный байт располагается слева. Поскольку значения ширины и длины меньше 255, они умещаются в последний байт каждой последовательности. Вы можете убедиться в том, что эти шестнадцатеричные значения соответствуют ожидаемым десятичным значениям:
>>> 0x9a
154
>>> 0x8d
141
Если вы хотите отправить их в противоположном направлении и преобразовать данные Python в байты, используйте функцию pack() модуля struct:
>>> import struct
>>> struct.pack('>L', 154)
b'\x00\x00\x00\x9a'
>>> struct.pack('>L', 141)
b'\x00\x00\x00\x8d'
В табл. 7.5 и 7.6 показаны спецификаторы формата для функций pack() и unpack(). Спецификаторы порядка байтов располагаются первыми в строке формата.
Спецификатор | Порядок байтов |
---|---|
< | Прямой порядок |
> | Обратный порядок |
Спецификатор | Описание | Количество байтов |
---|---|---|
x | Пропустить байт | 1 |
b | Знаковый байт | 1 |
B | Беззнаковый байт | 1 |
h | Знаковое короткое целое число | 2 |
H | Беззнаковое короткое целое число | 2 |
i | Знаковое целое число | 4 |
I | Беззнаковое целое число | 4 |
l | Знаковое длинное целое число | 4 |
L | Беззнаковое длинное целое число | 4 |
Q | Беззнаковое очень длинное целое число | 8 |
f | Число с плавающей точкой | 4 |
d | Число с плавающей точкой двойной точности | 8 |
p | Счетчик и символы | 1 + count |
s | Символы | count |
Спецификаторы типа следуют за символом, указывающим порядок байтов. Перед любым спецификатором может следовать число, которое указывает количество; запись 5B аналогична записи BBBBB.
Вы можете использовать префикс счетчика вместо конструкции >LL:
>>> struct.unpack('>2L', data[16:24])
(154, 141)
Мы использовали разбиение data[16:24], чтобы получить непосредственно интересующие нас байты. Мы также могли добавить спецификатор x, чтобы пропустить неинтересные части:
>>> struct.unpack('>16x2L6x', data)
(154, 141)
Эта строка означает:
• использовать формат с обратным порядком байтов (>);
• пропустить 16 байт (16x);
• прочесть 8 байт — два беззнаковых длинных целых числа (2L);
• пропустить последние 6 байт (6x).
Другие инструменты для работы с бинарными данными
Некоторые сторонние пакеты с открытым исходным кодом часто предлагают следующие более декларативные способы определения и извлечения бинарных данных:
• bitstring (http://bit.ly/py-bitstring);
• construct (http://bit.ly/py-construct);
• hachoir (http://bit.ly/hachoir-pkg);
• binio (http://spika.net/py/binio/).
В приложении Г содержатся инструкции о том, как загрузить и установить внешние пакеты вроде этих. Для следующего примера вам нужно установить пакет construct. Вот все, что вам необходимо сделать:
$ pip install construct
Вот так можно извлечь измерения PNG из нашей строки байтов data с помощью пакета construct:
>>> from construct import Struct, Magic, UBInt32, Const, String
>>> # адаптировано из кода по адресу https://github.com/construct
>>> fmt = Struct('png',
…·····Magic(b'\x89PNG\r\n\x1a\n'),
…·····UBInt32('length'),
…·····Const(String('type', 4), b'IHDR'),
…·····UBInt32('width'),
…·····UBInt32('height')
…·····)
>>> data = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR' + \
…·····b'\x00\x00\x00\x9a\x00\x00\x00\x8d\x08\x02\x00\x00\x00\xc0'
>>> result = fmt.parse(data)