Рубрики
Без рубрики

struct – структуры двоичных данных

Автор оригинала: Doug Hellmann.

Цель:

Преобразование между строками и двоичными данными.

Модуль struct включает функции для преобразования между строками байтов и собственными типами данных Python, такими как числа и строки.

Функции против класса Struct

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

Упаковка и распаковка

Структуры поддерживают упаковку данных в строки и распаковку данных из строк с использованием спецификаторов формата, состоящих из символов, представляющих тип данных, и необязательных индикаторов количества и порядка байтов. Обратитесь к документации стандартной библиотеки за полным списком поддерживаемых спецификаторов формата.

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

struct_pack.py

import struct
import binascii

values  (1, 'ab'.encode('utf-8'), 2.7)
s  struct.Struct('I 2s f')
packed_data  s.pack(*values)

print('Original values:', values)
print('Format string  :', s.format)
print('Uses           :', s.size, 'bytes')
print('Packed Value   :', binascii.hexlify(packed_data))

В примере упакованное значение преобразуется в последовательность шестнадцатеричных байтов для печати с помощью binascii.hexlify () , поскольку некоторые символы являются нулевыми.

$ python3 struct_pack.py

Original values: (1, b'ab', 2.7)
Format string  : I 2s f
Uses           : 12 bytes
Packed Value   : b'0100000061620000cdcc2c40'

Используйте unpack () для извлечения данных из упакованного представления.

struct_unpack.py

import struct
import binascii

packed_data  binascii.unhexlify(b'0100000061620000cdcc2c40')

s  struct.Struct('I 2s f')
unpacked_data  s.unpack(packed_data)
print('Unpacked Values:', unpacked_data)

Передача упакованного значения в unpack () возвращает в основном те же значения (обратите внимание на расхождение в значениях с плавающей запятой).

$ python3 struct_unpack.py

Unpacked Values: (1, b'ab', 2.700000047683716)

Порядок байтов

По умолчанию значения кодируются с использованием понятия endianness из собственной библиотеки C. Этот выбор легко изменить, указав явную директиву порядка байтов в строке формата.

struct_endianness.py

import struct
import binascii

values  (1, 'ab'.encode('utf-8'), 2.7)
print('Original values:', values)

endianness  [
    ('@', 'native, native'),
    (, 'native, standard'),
    ('<', 'little-endian'),
    ('>', 'big-endian'),
    ('!', 'network'),
]

for code, name in endianness:
    s  struct.Struct(code + ' I 2s f')
    packed_data  s.pack(*values)
    print()
    print('Format string  :', s.format, 'for', name)
    print('Uses           :', s.size, 'bytes')
    print('Packed Value   :', binascii.hexlify(packed_data))
    print('Unpacked Value :', s.unpack(packed_data))

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

Спецификаторы порядка байтов для структуры

Код

Смысл

Родной порядок

Родной стандарт

прямой порядок байтов

прямой порядок байтов

Сетевой заказ

$ python3 struct_endianness.py

Original values: (1, b'ab', 2.7)

Format string  : @ I 2s f for native, native
Uses           : 12 bytes
Packed Value   : b'0100000061620000cdcc2c40'
Unpacked Value : (1, b'ab', 2.700000047683716)

Format string  : = I 2s f for native, standard
Uses           : 10 bytes
Packed Value   : b'010000006162cdcc2c40'
Unpacked Value : (1, b'ab', 2.700000047683716)

Format string  : < I 2s f for little-endian
Uses           : 10 bytes
Packed Value   : b'010000006162cdcc2c40'
Unpacked Value : (1, b'ab', 2.700000047683716)

Format string  : > I 2s f for big-endian
Uses           : 10 bytes
Packed Value   : b'000000016162402ccccd'
Unpacked Value : (1, b'ab', 2.700000047683716)

Format string  : ! I 2s f for network
Uses           : 10 bytes
Packed Value   : b'000000016162402ccccd'
Unpacked Value : (1, b'ab', 2.700000047683716)

Буферы

Работа с двоичными упакованными данными обычно зарезервирована для ситуаций, чувствительных к производительности, или для передачи данных в модули расширения и из них. Эти случаи можно оптимизировать, избегая накладных расходов на выделение нового буфера для каждой упакованной структуры. Методы pack_into () и unpack_from () поддерживают запись непосредственно в предварительно выделенные буферы.

struct_buffers.py

import array
import binascii
import ctypes
import struct

s  struct.Struct('I 2s f')
values  (1, 'ab'.encode('utf-8'), 2.7)
print('Original:', values)

print()
print('ctypes string buffer')

b  ctypes.create_string_buffer(s.size)
print('Before  :', binascii.hexlify(b.raw))
s.pack_into(b, 0, *values)
print('After   :', binascii.hexlify(b.raw))
print('Unpacked:', s.unpack_from(b, 0))

print()
print('array')

a  array.array('b', b'\0' * s.size)
print('Before  :', binascii.hexlify(a))
s.pack_into(a, 0, *values)
print('After   :', binascii.hexlify(a))
print('Unpacked:', s.unpack_from(a, 0))

Атрибут size в Struct сообщает нам, насколько большим должен быть буфер.

$ python3 struct_buffers.py

Original: (1, b'ab', 2.7)

ctypes string buffer
Before  : b'000000000000000000000000'
After   : b'0100000061620000cdcc2c40'
Unpacked: (1, b'ab', 2.700000047683716)

array
Before  : b'000000000000000000000000'
After   : b'0100000061620000cdcc2c40'
Unpacked: (1, b'ab', 2.700000047683716)

Смотрите также