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. Выбор между нативным порядком байтов и заполнителями и стандартными форматами зависит от приложения.
Кроме того, первый символ строки формата можно использовать, чтобы задать порядок байтов, размер и выравнивание упакованных данных согласно следующей таблице:
Символ | Порядок байтов | Размер | Выравнивание |
|---|---|---|---|
| нативный | нативный | нативное |
| нативный | стандартный | нет |
| от младшего к старшему (little-endian) | стандартный | нет |
| от старшего к младшему (big-endian) | стандартный | нет |
| сетевой (= big-endian) | стандартный | нет |
Если первый символ не входит в этот список, предполагается '@'.
Примечание
Число 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 | логическое значение | 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, определённому стандартами C начиная с C99. В стандартном режиме он представлен одним байтом. -
При попытке упаковать нецелое число с использованием любого кода преобразования целых чисел, если у этого значения есть метод
__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: на типичной машине для хранения можно использовать unsigned short, но не для математических операций. Дополнительные сведения см. на странице Википедии, посвящённой формату чисел с плавающей точкой половинной точности. - При упаковке
'x'вставляет один байт NUL. - Символ формата
'p'кодирует «строку Pascal», то есть строку переменной длины, хранящуюся в фиксированном количестве байтов, заданном счётчиком. Первый сохранённый байт содержит длину строки или число 255, если длина больше. За ним следуют байты строки. Если строка, переданная вpack(), слишком длинная (длиннее, чем счётчик минус 1), сохраняются только первыеcount-1байтов строки. Если строка корочеcount-1, она дополняется нулевыми байтами, чтобы общее количество использованных байтов точно соответствовало счётчику. Обратите внимание: при вызовеunpack()символ формата'p'занимаетcountбайтов, однако возвращаемая строка не может содержать более 255 байтов. - Для символа формата
's'счётчик интерпретируется как длина байтов, а не как число повторений, как для остальных символов формата; например,'10s'означает одну строку длиной 10 байтов, преобразуемую в одну строку байтов Python или обратно, тогда как'10c'означает 10 отдельных односимвольных элементов длиной в один байт (например,cccccccccc), преобразуемых в десять разных объектов bytes 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' приводит к добавлению двух байтов-заполнителей в конце, если длинные целые числа на платформе выровнены по границе в 4 байта:
>>> 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 поддерживают следующие методы и атрибуты:
-
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.12/library/struct.html