Содержание страницы
6.3. struct – Интерпретация байтов как упакованных двоичных данных¶struct – Interpret bytes as packed binary data
Этот модуль выполняет преобразования между значениями Python и C-структурами, представленными в виде объектов Python bytes. Его можно использовать для обработки двоичных данных, хранящихся в файлах или получаемых из сетевых соединений, а также других источников. Он использует строки форматирования как компактное описание структуры C-структур и предполагаемого преобразования в/из значений Python.
Примечание
По умолчанию результат упаковки заданной C-структуры включает байты заполнения для сохранения правильного выравнивания задействованных C-типов; аналогично выравнивание учитывается при распаковке. Такое поведение выбрано для того, чтобы байты упакованной структуры в точности соответствовали расположению в памяти соответствующей C-структуры. Для обработки платформо-независимых форматов данных или отказа от неявных байтов заполнения используйте стандартный размер и выравнивание вместо собственного размера и выравнивания: подробнее см. Порядок байтов, размер и выравнивание.
6.3.1. Функции и исключения¶Functions and Exceptions
Модуль определяет следующие исключения и функции:
- exception struct.error¶
Исключение, вызываемое в различных ситуациях; аргумент – строка, описывающая, что не так.
- struct.pack(fmt, v1, v2, ...)¶
Возвращает объект bytes, содержащий значения v1, v2, ..., упакованные в соответствии со строкой форматирования fmt. Аргументы должны точно соответствовать значениям, требуемым форматом.
- struct.pack_into(fmt, buffer, offset, v1, v2, ...)¶
Упаковывает значения v1, v2, ... в соответствии со строкой формата fmt и записывает упакованные байты в буфер buffer, начиная с позиции offset. Обратите внимание: offset – обязательный аргумент.
- struct.unpack(fmt, buffer)¶
Распаковывает из буфера buffer (предположительно упакованного с помощью pack(fmt, ...)) в соответствии со строкой форматирования fmt. Результатом является кортеж, даже если он содержит ровно один элемент. Буфер должен содержать ровно столько данных, сколько требуется форматом (len(bytes) должно равняться calcsize(fmt)).
- struct.unpack_from(fmt, buffer, offset=0)¶
Распаковывает из buffer, начиная с позиции offset, в соответствии со строкой форматирования fmt. Результатом является кортеж, даже если он содержит ровно один элемент. buffer должен содержать как минимум столько данных, сколько требуется форматом (len(buffer[offset:]) должно быть не меньше calcsize(fmt)).
- struct.calcsize(fmt)¶
Возвращает размер структуры (и, следовательно, объекта bytes, создаваемого pack(fmt, ...)), соответствующий строке форматирования fmt.
6.3.2. Строки формата¶Format Strings
Строки формата – это механизм, используемый для указания ожидаемого расположения данных при упаковке и распаковке. Они составляются из символов формата, которые задают тип упаковываемых/распаковываемых данных. Кроме того, существуют специальные символы для управления порядком байтов, размером и выравниванием.
6.3.2.1. Порядок байтов, размер и выравнивание¶Byte Order, Size, and Alignment
По умолчанию типы C представляются в собственном формате и порядке байтов машины и правильно выравниваются путём пропуска байтов заполнения при необходимости (в соответствии с правилами, используемыми компилятором C).
В качестве альтернативы, первый символ строки формата может использоваться для указания порядка байтов, размера и выравнивания упакованных данных, как показано в следующей таблице:
| Символ | Порядок байтов | Размер | Выравнивание |
|---|---|---|---|
| @ | собственный | собственный | собственный |
| = | собственный | стандартный | нет |
| < | little-endian | стандартный | нет |
| > | big-endian | стандартный | нет |
| ! | сетевой порядок байт (= big-endian) | стандартный | нет |
Если первый символ не один из этих, предполагается '@'.
Собственный порядок байтов может быть big-endian или little-endian в зависимости от хост-системы. Например, Intel x86 и AMD64 (x86-64) используют little-endian; Motorola 68000 и PowerPC G5 – big-endian; ARM и Intel Itanium поддерживают переключаемый порядок байтов (bi-endian). Используйте sys.byteorder для проверки порядка байтов вашей системы.
Собственный размер и выравнивание определяются с помощью выражения sizeof компилятора C. Это всегда сочетается с собственным порядком байтов.
Стандартный размер зависит только от символа формата; см. таблицу в разделе Символы формата.
Обратите внимание на различие между '@' и '=': оба используют собственный порядок байт, но размер и выравнивание второго стандартизированы.
Форма '!' доступна для тех несчастных, кто утверждает, что не может запомнить, является ли сетевой порядок байтов big-endian или little-endian.
Нет способа указать несобственный порядок байт (принудительную перестановку байт); используйте соответствующий выбор из '<' или '>'.
Примечания:
- Заполнение автоматически добавляется только между последовательными членами структуры. Начало и конец закодированной структуры не дополняются.
- Заполнение не добавляется при использовании несобственного размера и выравнивания, например, с ‘<’, ‘>’, ‘=’ и ‘!’.
- Чтобы выровнять конец структуры по требованию выравнивания конкретного типа, завершите формат кодом этого типа с нулевым количеством повторений. См. Примеры.
6.3.2.2. Символы формата¶Format Characters
Символы формата имеют следующее значение; преобразование между значениями C и Python должно быть очевидным, исходя из их типов. Столбец «Стандартный размер» указывает размер упакованного значения в байтах при использовании стандартного размера; то есть когда строка формата начинается с одного из '<', '>', '!' или '='. При использовании собственного размера размер упакованного значения зависит от платформы.
| Формат | Тип C | Тип Python | Стандартный размер | Примечания |
|---|---|---|---|---|
| x | байт заполнения | нет значения | ||
| c | char | строка байт длиной 1 | 1 | |
| b | знаковый char | целое число | 1 | (1),(3) |
| B | unsigned char | целое число | 1 | (3) |
| ? | _Bool | bool | 1 | (1) |
| h | short | целое число | 2 | (3) |
| H | unsigned short | целое число | 2 | (3) |
| i | int | целое число | 4 | (3) |
| I | unsigned int | целое число | 4 | (3) |
| l | long | целое число | 4 | (3) |
| L | unsigned long | целое число | 4 | (3) |
| q | long long | целое число | 8 | (2), (3) |
| Q | unsigned long long | целое число | 8 | (2), (3) |
| f | float | float | 4 | (4) |
| d | double | float | 8 | (4) |
| s | char[] | байты | ||
| p | char[] | байты | ||
| P | void * | целое число | (5) |
Примечания:
Код преобразования '?' соответствует типу _Bool, определённому в C99. Если этот тип недоступен, он имитируется с помощью char. В стандартном режиме он всегда представлен одним байтом.
Коды преобразования 'q' и 'Q' доступны в родном режиме, только если компилятор C платформы поддерживает C long long или, в Windows, __int64. Они всегда доступны в стандартных режимах.
При попытке упаковать нецелое число с помощью любого из кодов целочисленного преобразования, если у нецелого числа есть метод __index__(), то этот метод вызывается для преобразования аргумента в целое число перед упаковкой.
Изменено в версии 3.2: Использование метода __index__() для нецелых чисел появилось в версии 3.2.
Для кодов преобразования 'f' и 'd' упакованное представление использует формат IEEE 754 binary32 (для 'f') или binary64 (для 'd'), независимо от формата чисел с плавающей запятой, используемого платформой.
Символ формата 'P' доступен только для родного порядка байтов (выбранного по умолчанию или с помощью символа порядка байтов '@'). Символ порядка байтов '=' выбирает порядок little- или big-endian в зависимости от хост-системы. Модуль struct не интерпретирует это как родной порядок, поэтому формат 'P' недоступен.
Символу формата может предшествовать целочисленный счетчик повторений. Например, строка формата '4h' означает то же самое, что и 'hhhh'.
Пробельные символы между форматами игнорируются; однако счётчик и его формат не должны содержать пробелов.
Для символа формата 's' счетчик интерпретируется как длина строки в байтах, а не как счетчик повторений, как для других символов формата; например, '10s' означает одну строку из 10 байтов, тогда как '10c' означает 10 символов. Если счетчик не задан, по умолчанию он равен 1. При упаковке строка усекается или дополняется нулевыми байтами по мере необходимости, чтобы соответствовать. При распаковке результирующий объект bytes всегда содержит ровно указанное количество байтов. Как частный случай, '0s' означает одну пустую строку (тогда как '0c' означает 0 символов).
При упаковке значения x с использованием одного из целочисленных форматов ('b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q'), если x выходит за допустимый диапазон для этого формата, то возбуждается struct.error.
Изменено в версии 3.1: В версии 3.0 некоторые целочисленные форматы оборачивали значения, выходящие за пределы диапазона, и выдавали DeprecationWarning вместо struct.error.
Символ формата 'p' кодирует «строку Паскаля», то есть короткую строку переменной длины, хранящуюся в фиксированном количестве байтов, заданном счетчиком. Первый сохраненный байт – это длина строки или 255, в зависимости от того, что меньше. Затем следуют байты строки. Если строка, переданная в pack(), слишком длинная (длиннее, чем count минус 1), сохраняются только первые count-1 байтов строки. Если строка короче count-1, она дополняется нулевыми байтами, так что всего используется ровно count байтов. Обратите внимание, что для unpack() символ формата 'p' потребляет count байтов, но возвращаемая строка никогда не может содержать более 255 байтов.
Для символа формата '?' возвращаемым значением является либо True, либо False. При упаковке используется истинностное значение объекта-аргумента. Будет упакован либо 0, либо 1 в нативном или стандартном представлении bool, а при распаковке любое ненулевое значение станет True.
6.3.2.3. Примеры¶Examples
Примечание
Все примеры предполагают собственный порядок байтов, размер и выравнивание на машине с big-endian.
Простой пример упаковки/распаковки трёх целых чисел:
>>> from struct import *
>>> pack('hhl', 1, 2, 3)
b'\x00\x01\x00\x02\x00\x00\x00\x03'
>>> unpack('hhl', b'\x00\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
>>> calcsize('hhl')
8
Распакованные поля можно именовать, присваивая их переменным или оборачивая результат в именованный кортеж:
>>> record = b'raymond \x32\x12\x08\x01\x08'
>>> name, serialnum, school, gradelevel = unpack('<10sHHb', record)
>>> from collections import namedtuple
>>> Student = namedtuple('Student', 'name serialnum school gradelevel')
>>> Student._make(unpack('<10sHHb', record))
Student(name=b'raymond ', serialnum=4658, school=264, gradelevel=8)
Порядок символов формата может влиять на размер, поскольку заполнение, необходимое для удовлетворения требований выравнивания, отличается:
>>> pack('ci', b'*', 0x12131415)
b'*\x00\x00\x00\x12\x13\x14\x15'
>>> pack('ic', 0x12131415, b'*')
b'\x12\x13\x14\x15*'
>>> calcsize('ci')
8
>>> calcsize('ic')
5
Следующий формат 'llh0l' указывает два байта заполнения в конце, при условии, что значения long выровнены по границе 4 байта:
>>> pack('llh0l', 1, 2, 3)
b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'
Это работает только при использовании собственного размера и выравнивания; стандартный размер и выравнивание не обеспечивают никакого выравнивания.
6.3.3. Классы¶Classes
Модуль struct также определяет следующий тип:
- class struct.Struct(format)¶
Возвращает новый объект Struct, который записывает и читает бинарные данные в соответствии со строкой формата format. Создание объекта Struct один раз и вызов его методов более эффективно, чем вызов функций struct с тем же форматом, поскольку строку формата нужно скомпилировать только один раз.
Скомпилированные объекты Struct поддерживают следующие методы и атрибуты:
- pack(v1, v2, ...)¶
Идентично функции pack() с использованием скомпилированного формата. (len(result) будет равно self.size.)
- pack_into(buffer, offset, v1, v2, ...)¶
Идентично функции pack_into() с использованием скомпилированного формата.
- unpack(buffer)¶
Идентично функции unpack() с использованием скомпилированного формата. (len(buffer) должно быть равно self.size).
- unpack_from(buffer, offset=0)¶
Идентично функции unpack_from() с использованием скомпилированного формата. (len(buffer[offset:]) должно быть не менее self.size).
- format¶
Строка форматирования, используемая для создания этого объекта Struct.