struct — Интерпретация байтов как упакованных двоичных данных
Исходный код: Lib/struct.py
Этот модуль преобразует значения Python в структуры C, представленные объектами Python bytes, и обратно. Компактные строки формата описывают предполагаемые преобразования значений Python и обратно. Функции и объекты модуля можно использовать для двух в значительной степени различных задач: обмена данными с внешними источниками (файлами или сетевыми подключениями) или передачи данных между приложением Python и уровнем C.
Примечание
Если символ префикса не указан, по умолчанию используется собственный режим. Данные упаковываются или распаковываются с учётом платформы и компилятора, с которыми была собрана среда выполнения Python. Результат упаковки заданной структуры C содержит байты-заполнители, поддерживающие правильное выравнивание задействованных типов C; при распаковке выравнивание также учитывается. Напротив, при обмене данными с внешними источниками программист отвечает за определение порядка байтов и заполнения между элементами. Подробности см. в разделе Порядок байтов, размер и выравнивание.
Некоторые функции struct (и методы Struct) принимают аргумент buffer. Он обозначает объекты, которые реализуют протокол буферов и предоставляют буфер только для чтения или для чтения и записи. Чаще всего для этой цели используются типы bytes и bytearray, однако многие другие типы, которые можно рассматривать как массив байтов, реализуют протокол буферов, позволяя читать данные из объекта bytes или заполнять его без дополнительного копирования.
Функции и исключения
Модуль определяет следующее исключение и функции:
-
exception struct.error -
Исключение, вызываемое в различных случаях; аргумент — строка с описанием ошибки.
-
struct.pack(format, v1, v2, ...) -
Возвращает объект bytes, содержащий значения v1, v2, …, упакованные в соответствии со строкой формата format. Аргументы должны точно соответствовать значениям, требуемым форматом.
-
struct.pack_into(format, buffer, offset, v1, v2, ...) -
Упаковывает значения v1, v2, … в соответствии со строкой формата format и записывает упакованные байты в доступный для записи буфер buffer, начиная с позиции offset. Обратите внимание: аргумент offset обязателен.
-
struct.unpack(format, buffer) -
Распаковывает данные из буфера buffer (предположительно упакованные с помощью
pack(format, ...)) в соответствии со строкой формата format. Результатом всегда является кортеж, даже если он содержит ровно один элемент. Размер буфера в байтах должен совпадать с размером, требуемым форматом, как показываетcalcsize().
-
struct.unpack_from(format, /, buffer, offset=0) -
Распаковывает данные из buffer, начиная с позиции offset, в соответствии со строкой формата format. Результатом всегда является кортеж, даже если он содержит ровно один элемент. Размер буфера в байтах, начиная с позиции offset, должен быть не меньше размера, требуемого форматом, как показывает
calcsize().
-
struct.iter_unpack(format, buffer) -
Последовательно распаковывает данные из буфера buffer в соответствии со строкой формата format. Эта функция возвращает итератор, который считывает из буфера фрагменты одинакового размера, пока не будут обработаны все его данные. Размер буфера в байтах должен быть кратен размеру, требуемому форматом, как показывает
calcsize().На каждой итерации возвращается кортеж, определённый строкой формата.
Добавлено в версии 3.4.
-
struct.calcsize(format) -
Возвращает размер структуры (а значит, и объекта bytes, созданного с помощью
pack(format, ...)), соответствующей строке формата format.
Строки формата
Строки формата описывают расположение данных при их упаковке и распаковке. Они состоят из символов формата, задающих тип упаковываемых или распаковываемых данных. Кроме того, специальные символы задают порядок байтов, размер и выравнивание. Каждая строка формата состоит из необязательного символа префикса, описывающего общие свойства данных, и одного или нескольких символов формата, описывающих фактические значения данных и заполнение.
Порядок байтов, размер и выравнивание
По умолчанию типы C представлены в собственном машинном формате и порядке байтов, а также правильно выровнены за счёт пропуска байтов-заполнителей, если это необходимо (в соответствии с правилами используемого компилятора C). Такое поведение выбрано для того, чтобы байты упакованной структуры точно соответствовали расположению в памяти соответствующей структуры C. Выбор между собственным порядком байтов и заполнением или стандартными форматами зависит от приложения.
Кроме того, первый символ строки формата можно использовать для указания порядка байтов, размера и выравнивания упакованных данных согласно следующей таблице:
Символ | Порядок байтов | Размер | Выравнивание |
|---|---|---|---|
| собственный | собственный | собственное |
| собственный | стандартный | отсутствует |
| от младшего байта к старшему | стандартный | отсутствует |
| от старшего байта к младшему | стандартный | отсутствует |
| сетевой (= от старшего байта к младшему) | стандартный | отсутствует |
Если первый символ не входит в этот список, предполагается '@'.
Примечание
Число 1023 (0x3ff в шестнадцатеричной системе) представляется байтами следующим образом:
-
03 ffпри порядке байтов от старшего к младшему (>) -
ff 03при порядке байтов от младшего к старшему (<)
Пример на Python:
>>> import struct
>>> struct.pack('>h', 1023)
b'\x03\xff'
>>> struct.pack('<h', 1023)
b'\xff\x03'
Собственный порядок байтов бывает от старшего к младшему или от младшего к старшему в зависимости от системы. Например, Intel x86, AMD64 (x86-64) и Apple M1 используют порядок от младшего байта к старшему; IBM z и многие устаревшие архитектуры — порядок от старшего байта к младшему. Используйте sys.byteorder, чтобы проверить порядок байтов в системе.
Собственные размер и выравнивание определяются с помощью выражения sizeof компилятора C. Они всегда сочетаются с собственным порядком байтов.
Стандартный размер зависит только от символа формата; см. таблицу в разделе Символы формата.
Обратите внимание на разницу между '@' и '=': оба используют собственный порядок байтов, но размер и выравнивание второго стандартизированы.
Форма '!' обозначает сетевой порядок байтов, который всегда соответствует порядку от старшего байта к младшему, как определено в IETF RFC 1700.
Указать порядок байтов, отличный от собственного (принудительно изменить порядок байтов), невозможно; используйте соответствующий вариант '<' или '>'.
Примечания:
- Заполнение автоматически добавляется только между последовательными членами структуры. В начале или конце закодированной структуры заполнение не добавляется.
- При использовании нестандартных размера и выравнивания заполнение не добавляется, например при использовании ‘<’, ‘>’, ‘=’ и ‘!’.
- Чтобы выровнять конец структуры согласно требованиям к выравниванию определённого типа, завершите формат кодом этого типа с нулевым числом повторений. См. раздел Примеры.
Символы формата
Символы формата имеют следующие значения; преобразование между значениями C и Python должно быть очевидным с учётом их типов. Столбец «Стандартный размер» указывает размер упакованного значения в байтах при использовании стандартного размера, то есть если строка формата начинается с одного из символов '<', '>', '!' или '='. При использовании собственного размера размер упакованного значения зависит от платформы.
Формат | Тип C | Тип Python | Стандартный размер | Примечания |
|---|---|---|---|---|
| байт-заполнитель | значение отсутствует | (7) | |
| char | байты длиной 1 | 1 | |
| signed char | целое число | 1 | (1), (2) |
| unsigned char | целое число | 1 | (2) |
| _Bool | bool | 1 | (1) |
| short | целое число | 2 | (2) |
| unsigned short | целое число | 2 | (2) |
| int | целое число | 4 | (2) |
| unsigned int | целое число | 4 | (2) |
| long | целое число | 4 | (2) |
| unsigned long | целое число | 4 | (2) |
| long long | целое число | 8 | (2) |
| unsigned long long | целое число | 8 | (2) |
|
| целое число | (3) | |
|
| целое число | (3) | |
| (6) | число с плавающей точкой | 2 | (4) |
| float | число с плавающей точкой | 4 | (4) |
| double | число с плавающей точкой | 8 | (4) |
| char[] | байты | (9) | |
| char[] | байты | (8) | |
| void* | целое число | (5) |
Изменено в версии 3.3: Добавлена поддержка форматов 'n' и 'N'.
Изменено в версии 3.6: Добавлена поддержка формата 'e'.
Примечания:
- Код преобразования
'?'соответствует типу _Bool, определённому стандартом C99. Если этот тип недоступен, вместо него используется тип char. В стандартном режиме он всегда представлен одним байтом. -
При попытке упаковать нецелое значение с помощью любого кода преобразования целых чисел, если у нецелого значения есть метод
__index__(), этот метод вызывается для преобразования аргумента в целое число перед упаковкой.Изменено в версии 3.2: Добавлено использование метода
__index__()для нецелых значений. - Коды преобразования
'n'и'N'доступны только для собственного размера (выбирается по умолчанию или с помощью символа порядка байтов'@'). Для стандартного размера можно использовать любой другой целочисленный формат, подходящий для вашей задачи. - Для кодов преобразования
'f','d'и'e'упакованное представление использует формат IEEE 754 binary32, binary64 или binary16 (соответственно для'f','d'или'e'), независимо от формата чисел с плавающей точкой, используемого платформой. - Символ формата
'P'доступен только для собственного порядка байтов (выбирается по умолчанию или с помощью символа порядка байтов'@'). Символ порядка байтов'='выбирает порядок от младшего байта к старшему или от старшего байта к младшему в зависимости от системы. Модуль struct не считает его собственным порядком, поэтому формат'P'недоступен. - Тип IEEE 754 binary16 «половинной точности» был введён в редакции стандарта IEEE 754 2008 года. У него есть знаковый бит, 5-битная экспонента и точность 11 бит (10 бит хранятся явно); он может представлять числа в диапазоне приблизительно от
6.1e-05до6.5e+04с полной точностью. Этот тип широко не поддерживается компиляторами C: на типичной машине для хранения можно использовать беззнаковое короткое целое, но не для математических операций. Дополнительные сведения см. на странице Википедии о формате чисел с плавающей точкой половинной точности. - При упаковке
'x'вставляет один байт NUL. - Символ формата
'p'кодирует «строку Паскаля», то есть строку переменной длины, хранящуюся в фиксированном количестве байтов, заданном числом повторений. Первый сохранённый байт содержит длину строки или число 255 — в зависимости от того, что меньше. За ним следуют байты строки. Если строка, переданная вpack(), слишком длинная (длиннее числа повторений минус 1), сохраняются только первыеcount-1байтов строки. Если строка корочеcount-1, она дополняется нулевыми байтами так, чтобы общее количество используемых байтов точно равнялось числу повторений. Обратите внимание: при вызовеunpack()символ формата'p'занимаетcountбайтов, но возвращаемая строка никогда не может содержать более 255 байтов. - Для символа формата
's'число повторений трактуется как длина последовательности байтов, а не как количество повторений, как для других символов формата; например,'10s'означает одну строку длиной 10 байтов, которая преобразуется в одну строку байтов Python или обратно, а'10c'означает 10 отдельных однобайтовых символьных элементов (например,cccccccccc), преобразуемых в десять отдельных байтовых объектов Python или обратно. (Конкретный пример различия см. в разделе Примеры.) Если число повторений не указано, оно по умолчанию равно 1. При упаковке строка усекается или дополняется нулевыми байтами, чтобы соответствовать заданному размеру. При распаковке результирующий объект bytes всегда имеет точно указанное число байтов. Особый случай:'0s'означает одну пустую строку (тогда как'0c'означает 0 символов).
Перед символом формата может указываться целое число повторений. Например, строка формата '4h' полностью эквивалентна 'hhhh'.
Пробельные символы между форматами игнорируются, однако между числом повторений и символом формата пробелов быть не должно.
При упаковке значения x с помощью одного из целочисленных форматов ('b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q'), если x выходит за допустимый для этого формата диапазон, вызывается struct.error.
Изменено в версии 3.1: Ранее некоторые целочисленные форматы циклически преобразовывали значения, выходящие за допустимый диапазон, и вызывали DeprecationWarning вместо struct.error.
Для символа формата '?' возвращаемое значение — это либо True, либо False. При упаковке используется логическое значение объекта-аргумента. Будет упаковано значение 0 или 1 в собственном или стандартном представлении bool, а при распаковке любое ненулевое значение будет True.
Примеры
Примечание
Примеры с собственным порядком байтов (обозначенным префиксом формата '@' или отсутствием символа префикса) могут не совпадать с результатом на компьютере читателя, поскольку он зависит от платформы и компилятора.
Упаковка и распаковка целых чисел трёх разных размеров с использованием порядка байтов от старшего к младшему:
>>> from struct import *
>>> pack(">bhl", 1, 2, 3)
b'\x01\x00\x02\x00\x00\x00\x03'
>>> unpack('>bhl', b'\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
>>> calcsize('>bhl')
7
Попытка упаковать целое число, слишком большое для заданного поля:
>>> pack(">h", 99999)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
struct.error: 'h' format requires -32768 <= number <= 32767
Демонстрация различия между символами формата 's' и 'c':
>>> pack("@ccc", b'1', b'2', b'3')
b'123'
>>> pack("@3s", b'123')
b'123'
Распакованным полям можно присвоить имена, сохранив их в переменных, или обернуть результат в именованный кортеж:
>>> 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 ниже после упакованного '#' были добавлены три байта NUL, чтобы выровнять следующее целое число по четырёхбайтовой границе. В этом примере результат получен на машине с порядком байтов от младшего к старшему:
>>> pack('@ci', b'#', 0x12131415)
b'#\x00\x00\x00\x15\x14\x13\x12'
>>> pack('@ic', 0x12131415, b'#')
b'\x15\x14\x13\x12#'
>>> calcsize('@ci')
8
>>> calcsize('@ic')
5
Следующий формат 'llh0l' приводит к добавлению в конце двух байтов-заполнителей, если предположить, что длинные целые числа на платформе выровнены по четырёхбайтовым границам:
>>> pack('@llh0l', 1, 2, 3)
b'\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x00'
Применение
Модуль struct имеет два основных варианта применения: обмен данными между кодом Python и кодом C внутри приложения или другого приложения, скомпилированного тем же компилятором (собственные форматы), а также обмен данными между приложениями с использованием согласованного расположения данных (стандартные форматы). Как правило, строки формата для этих двух областей различаются.
Собственные форматы
При создании строк формата, имитирующих собственное расположение данных, порядок байтов и заполнение определяются компилятором и архитектурой компьютера. В таких случаях для указания собственного порядка байтов и размеров данных следует использовать символ формата @. Внутренние байты-заполнители обычно добавляются автоматически. В конце строки формата может потребоваться код формата с нулевым числом повторений, чтобы округлить размер до правильной границы байтов для выравнивания последовательных фрагментов данных.
Рассмотрим два простых примера (на 64-разрядной машине с порядком байтов от младшего к старшему):
>>> calcsize('@lhl')
24
>>> calcsize('@llh')
18
Без дополнительного заполнения данные не выравниваются по 8-байтовой границе в конце второй строки формата. Эту проблему решает код формата с нулевым числом повторений:
>>> calcsize('@llh0l')
24
Код формата 'x' можно использовать для указания повторения, но для собственных форматов лучше подходит формат с нулевым числом повторений, например '0l'.
По умолчанию используются собственные порядок байтов и выравнивание, однако лучше указывать их явно с помощью символа префикса '@'.
Стандартные форматы
При обмене данными за пределами процесса, например по сети или при хранении, необходимо быть точным. Указывайте конкретные порядок байтов, размер и выравнивание. Не предполагайте, что они совпадают с собственным порядком определённой машины. Например, сетевой порядок байтов соответствует порядку от старшего байта к младшему, тогда как многие популярные процессоры используют порядок от младшего байта к старшему. Явное определение этих параметров избавляет пользователя от необходимости учитывать особенности платформы, на которой выполняется его код. В качестве первого символа обычно следует указывать < или > (либо !). За заполнение отвечает программист. Символ формата с нулевым числом повторений не сработает. Вместо этого пользователь должен явно добавлять 'x' байтов-заполнителей, где это необходимо. Если вернуться к примерам из предыдущего раздела, получим:
>>> calcsize('<qh6xq')
24
>>> pack('<qh6xq', 1, 2, 3) == pack('@lhl', 1, 2, 3)
True
>>> calcsize('@llh')
18
>>> pack('@llh', 1, 2, 3) == pack('<qqh', 1, 2, 3)
True
>>> calcsize('<qqh6x')
24
>>> calcsize('@llh0l')
24
>>> pack('@llh0l', 1, 2, 3) == pack('<qqh6x', 1, 2, 3)
True
Результаты выше (полученные на 64-разрядной машине) не гарантированно совпадут при выполнении на других машинах. Например, приведённые ниже примеры были выполнены на 32-разрядной машине:
>>> calcsize('<qqh6x')
24
>>> calcsize('@llh0l')
12
>>> pack('@llh0l', 1, 2, 3) == pack('<qqh6x', 1, 2, 3)
False
Классы
Модуль struct также определяет следующий тип:
-
class struct.Struct(format) -
Возвращает новый объект Struct, который записывает и считывает двоичные данные в соответствии со строкой формата format. Создать объект
Structодин раз и вызывать его методы эффективнее, чем вызывать функции уровня модуля с тем же форматом, поскольку строка формата компилируется только один раз.Примечание
Скомпилированные версии последних строк формата, переданных в
Structи функции уровня модуля, кэшируются, поэтому программам, использующим всего несколько строк формата, не нужно беспокоиться о повторном использовании одного экземпляраStruct.Скомпилированные объекты Struct поддерживают следующие методы и атрибуты:
-
pack(v1, v2, ...) -
Идентичен функции
pack(), использующей скомпилированный формат. (len(result)будет равенsize.)
-
pack_into(buffer, offset, v1, v2, ...) -
Идентичен функции
pack_into(), использующей скомпилированный формат.
-
unpack(buffer) -
Идентичен функции
unpack(), использующей скомпилированный формат. Размер буфера в байтах должен быть равенsize.
-
unpack_from(buffer, offset=0) -
Идентичен функции
unpack_from(), использующей скомпилированный формат. Размер буфера в байтах, начиная с позиции offset, должен быть не меньшеsize.
-
iter_unpack(buffer) -
Идентичен функции
iter_unpack(), использующей скомпилированный формат. Размер буфера в байтах должен быть кратенsize.Добавлено в версии 3.4.
-
format -
Строка формата, использованная для создания этого объекта Struct.
-
© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.11/library/struct.html