struct — Интерпретировать байты как упакованные двоичные данные

Исходный код: Lib/struct.py


Этот модуль преобразует значения Python в структуры C, представленные в виде объектов Python bytes. Compact format strings описывает предполагаемые преобразования в значения 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. Результатом будет кортеж, даже если он содержит ровно один элемент. Размер буфера в байтах, начиная с позиции смещение, должен быть как минимум таким, какой требуется форматом, как указано в calcsize().

struct.iter_unpack(format, buffer)

Выполните итеративную распаковку из буфера buffer в соответствии со строкой формата format. Эта функция возвращает итератор, который будет считывать фрагменты одинакового размера из буфера до тех пор, пока не будет использовано все его содержимое. Размер буфера в байтах должен быть кратен размеру, требуемому форматом, как указано в calcsize().

Каждая итерация приводит к получению кортежа, указанного в строке формата.

Добавлено в версии 3.4.

struct.calcsize(format)

Возвращает размер структуры (и, следовательно, объекта bytes, созданного с помощью pack(format, ...)), соответствующий строке формата format.

Форматирование строк

Строки формата описывают расположение данных при упаковке и распаковке данных. Они состоят из format characters, которые указывают тип упаковываемых/распаковываемых данных. Кроме того, специальные символы управляют byte order, size and alignment. Каждая строка формата состоит из необязательного префиксного символа, который описывает общие свойства данных, и одного или нескольких символов формата, которые описывают фактические значения данных и заполнение.

Порядок, размер и выравнивание байтов

По умолчанию типы 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, используемого компилятором языка Си. Это всегда сочетается с собственным порядком байтов.

Стандартный размер зависит только от символа формата; смотрите таблицу в разделе Форматирование символов.

Обратите внимание на разницу между '@' и '=': в обоих случаях используется собственный порядок байтов, но размер и выравнивание последнего стандартизированы.

Форма '!' представляет порядок байтов в сети, который всегда имеет большой порядок следования, как определено в IETF RFC 1700.

Нет способа указать неродной порядок байтов (принудительная замена байтов); используйте соответствующий вариант '<' или '>'.

Записи:

  1. Заполнение автоматически добавляется только между последовательными элементами структуры. Заполнение не добавляется ни в начале, ни в конце закодированной структуры.

  2. При использовании нестандартного размера и выравнивания отступы не добавляются, например, с помощью „<“, „>“, „=“, и „!“.

  3. Чтобы выровнять конец структуры в соответствии с требованиями к выравниванию для определенного типа, завершите формат кодом для этого типа с нулевым числом повторений. Смотрите Примеры.

Форматирование символов

Символы формата имеют следующее значение; преобразование между значениями C и Python должно быть очевидным, учитывая их типы. Столбец «Стандартный размер» относится к размеру упакованного значения в байтах при использовании стандартного размера; то есть, когда строка формата начинается с одного из '<', '>', '!' или '='. При использовании собственного размера размер упакованного значения зависит от платформы.

Формат

Тип C

Тип Python

Стандартный размер

Записи

x

байт pad

нет

(7)

c

char

байт длиной 1

1

b

signed char

целое число

1

(1), (2)

B

unsigned char

целое число

1

(2)

?

_Bool

тип bool

1

(1)

h

short

целое число

2

(2)

H

unsigned short

целое число

2

(2)

i

int

целое число

4

(2)

I

unsigned int

целое число

4

(2)

l

long

целое число

4

(2)

L

unsigned long

целое число

4

(2)

q

long long

целое число

8

(2)

Q

unsigned long long

целое число

8

(2)

n

ssize_t

целое число

(3)

N

size_t

целое число

(3)

e

(6)

плыть

2

(4)

f

float

плыть

4

(4)

d

double

плыть

8

(4)

s

char[]

байты

(9)

p

char[]

байты

(8)

P

void*

целое число

(5)

Изменено в версии 3.3: Добавлена поддержка форматов 'n' и 'N'.

Изменено в версии 3.6: Добавлена поддержка формата 'e'.

Записи:

  1. Код преобразования '?' соответствует типу _Bool, определяемому C99. Если этот тип недоступен, он моделируется с использованием char. В стандартном режиме он всегда представлен одним байтом.

  2. При попытке упаковать нецелое число с использованием любого из целочисленных кодов преобразования, если у нецелого числа есть метод __index__(), то этот метод вызывается для преобразования аргумента в целое число перед упаковкой.

    Изменено в версии 3.2: Добавлено использование метода __index__() для нецелых чисел.

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

  4. Для кодов преобразования 'f', 'd' и 'e' в упакованном представлении используется формат IEEE 754 binary32, binary64 или binary16 (для 'f', 'd' или 'e' соответственно), независимо от формата с плавающей запятой, используемого платформой.

  5. Символ формата 'P' доступен только для собственного порядка байтов (выбранного по умолчанию или с символом порядка байтов '@'). Символ порядка байтов '=' выбирает порядок с малым или большим числом байтов в зависимости от хост-системы. Модуль struct не интерпретирует это как собственный порядок, поэтому формат 'P' недоступен.

  6. Двоичный код стандарта IEEE 75416 с «половинной точностью» был введен в редакции стандарта IEEE 754 standard в 2008 году. Он имеет знаковый бит, 5-битный показатель степени и 11-битную точность (при явном сохранении 10 бит) и может представлять числа приблизительно от 6.1e-05 до 6.5e+04 с полной точностью. Этот тип не очень широко поддерживается компиляторами языка Си: на обычном компьютере беззнаковое сокращение может использоваться для хранения данных, но не для математических операций. Дополнительную информацию смотрите на странице Википедии в разделе half-precision floating-point format.

  7. При упаковке 'x' вставляет один нулевой байт.

  8. Символ формата 'p' кодирует «строку на языке Pascal», что означает короткую строку переменной длины, хранящуюся в фиксированном количестве байт, заданном параметром count. Первый сохраненный байт - это длина строки, или 255, в зависимости от того, что меньше. Далее следуют байты строки. Если строка, переданная в pack(), слишком длинная (длиннее, чем значение счетчика минус 1), сохраняются только начальные count-1 байта строки. Если строка короче, чем count-1, она дополняется нулевыми байтами, чтобы во всех использовалось точное количество байт. Обратите внимание, что для unpack() символ формата 'p' потребляет count байт, но возвращаемая строка никогда не может содержать более 255 байт.

  9. Для символа формата 's' количество интерпретируется как длина байтов, а не как количество повторений, как для других символов формата; например, '10s' означает одиночную 10-байтовую строку, сопоставляемую с одной строкой байтов Python или из нее, в то время как '10c' означает 10 отдельных однобайтовых символьных элементов (например, cccccccccc), сопоставляемых с десятью различными байтовыми объектами Python или из них. (Смотрите Примеры для конкретной демонстрации разницы.) Если значение count не указано, оно по умолчанию равно 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. При упаковке используется значение истинности объекта argument object. Будет упаковано либо 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 вызове, приведенном ниже, после упакованного '#' были добавлены три нулевых байта, чтобы выровнять следующее целое число по четырехбайтовой границе. В этом примере выходные данные были получены на компьютере с короткой системой счисления:

>>> 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'

См.также

Модуль array

Упакованное двоичное хранилище однородных данных.

Модуль json

Кодировщик и декодер JSON.

Модуль pickle

Сериализация объектов Python.

Приложения

Существуют два основных приложения для модуля struct: обмен данными между кодом на Python и C в приложении или другом приложении, скомпилированном с использованием того же компилятора (native formats), и обмен данными между приложениями с использованием согласованного расположения данных (standard formats). Вообще говоря, форматные строки, созданные для этих двух доменов, различны.

Собственные форматы

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

Рассмотрим эти два простых примера (на 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(), использующей скомпилированный формат. Размер буфера в байтах, начиная с позиции смещение, должен быть не менее size.

iter_unpack(buffer)

Аналогично функции iter_unpack(), использующей скомпилированный формат. Размер буфера в байтах должен быть кратен size.

Добавлено в версии 3.4.

format

Строка формата, используемая для построения этого объекта Struct.

Изменено в версии 3.7: Тип строки формата теперь str вместо bytes.

size

Вычисленный размер структуры (и, следовательно, объекта bytes, созданного методом pack()), соответствующий format.

Вернуться на верх