Двоичная информация в Python: типы и практические примеры

Раздел: Основы Python -> Типы данных

Работа с двоичными данными в Python

В Python двоичные данные представляются встроенными типами bytes и bytearray, а также модулями для их преобразования и анализа. Ниже приведены различные подходы к созданию, изменению и интерпретации бинарных данных.

Как эффективно упаковывать и распаковывать двоичные данные фиксированной структуры?

Для работы со структурированными двоичными данными (например, заголовки файлов, сетевые пакеты) применяется модуль struct. Он преобразует значения Python в байты и обратно в соответствии с форматом.

import struct
# Упаковка целого числа (4 байта) и строки (5 байт)
data = struct.pack('>I5s', 1024, b'hello')
print(data)  # b'\x00\x00\x04\x00hello'
# Распаковка
a, b = struct.unpack('>I5s', data)
print(a, b)  # 1024 b'hello'

Set str python (множество из строки в python)

Проблема: несоответствие порядка байтов (endianness) или размера типов. Решение - явно указывать формат ('<' Little-Endian, '>' Big-Endian, '!' сетевой порядок).

Типичная ошибка: передача строки без кодировки - строки должны быть байтами (b'...').

Как создать и изменить неизменяемую последовательность байтов?

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

b1 = b'Hello'
b2 = bytes([72, 101, 108, 108, 111])  # то же самое
b3 = bytes(10)  # 10 нулевых байтов
print(b1 == b2)  # True

Python переменная время (переменные для времени в python)

Проблема: попытка изменить элемент bytes вызовет TypeError. Для изменений используйте bytearray.

Как изменить двоичные данные на месте?

bytearray - изменяемый аналог bytes. Позволяет присваивать значения по индексу или срезу.

ba = bytearray(b'Python')
ba[0] = 74  # 74 -> 'J'
ba[1:4] = b'AVA'
print(ba)  # bytearray(b'JAVAn')

Python типы данных время (типы данных для времени в python)

Проблема: присваивание значения вне диапазона 0-255 вызывает ValueError. Необходимо проверять диапазон.

Как преобразовывать двоичные данные в шестнадцатеричный вид и обратно?

Модуль binascii предоставляет функции hexlify и unhexlify для работы с hex-строками.

import binascii
binary_data = b'\x00\x01\x02\xff'
hex_str = binascii.hexlify(binary_data).decode('ascii')
print(hex_str)  # '000102ff'
original = binascii.unhexlify(hex_str)
print(original)  # b'\x00\x01\x02\xff'

Python объект тип (тип объекта в python)

Проблема: результат hexlify - объект bytes, его нужно декодировать для строкового представления. При unhexlify строка должна содержать только hex-символы, иначе binascii.Error.

Как эффективно обращаться к срезам без копирования данных?

memoryview позволяет получать представление буфера без копирования, что полезно для больших двоичных массивов.

data = bytearray(b'This is a buffer')
view = memoryview(data)
slice_view = view[5:10]
print(slice_view.tobytes())  # b'is a '
# Изменение через view влияет на оригинал
view[0] = 84  # 'T' -> ascii 84 (совпадает, просто пример)
print(data)  # bytearray(b'This is a buffer')

вещественные значения python (вещественные значения в python)

Проблема: memoryview не поддерживает операции, требующие изменения размера. Также при работе с многомерными массивами (например, из модуля array) нужно указывать формат.

Как читать и записывать двоичные файлы?

Для работы с бинарными файлами файл открывается в режиме 'rb' или 'wb'. Затем используются методы read, write или struct для упаковки.

with open('data.bin', 'wb') as f:
    f.write(struct.pack('<Q', 123456789))  # 8 байт
with open('data.bin', 'rb') as f:
    value = struct.unpack('<Q', f.read(8))[0]
    print(value)  # 123456789

вывести тип данных python (вывод типа данных в python)

Проблема: несоответствие количества прочитанных байт ожидаемому - может привести к struct.error. Необходимо проверять длину данных.

Как выполнять битовые операции над байтами?

Битовые сдвиги, И, ИЛИ, НЕ применяются к целым числам. Для работы с отдельными битами байта можно преобразовать байт в int.

b = b'\x0f'  # 15
val = b[0]
val |= 0x10  # устанавливаем 5-й бит
val &= 0x1F   # маска для 5 бит
new_byte = bytes([val])
print(new_byte)  # b'\x1f' (31)

Проблема: при работе с большими последовательностями удобнее использовать массив целых чисел. Для представления битовой маски подходят целые числа произвольной длины (int).

- комплексные числа в python (комплексные числа в python)
- логические значения python (логические значения в python)
- длина переменной python (длина числа и переменной в python)

Расширенные примеры работы с двоичными данными

Ниже представлены дополнительные сценарии с подробными пояснениями и выводом результатов.

Чтение бинарного файла заголовка BMP

Пример
import struct
# Пример содержимого BMP-файла (заголовок 54 байта)
# Для демонстрации создадим минимальный BMP (1x1 пиксель)
# Размер файла 62 байта: 54 заголовка + 8 байт данных
# Формат: b'BM...'
bmp_bytes = (
    b'BM' +
    struct.pack('<I', 62) +   # размер файла
    struct.pack('<HH', 0, 0) +  # зарезервировано
    struct.pack('<I', 54) +   # смещение до данных
    struct.pack('<I', 40) +   # размер заголовка BITMAPINFOHEADER
    struct.pack('<ii', 1, 1) +  # ширина и высота
    struct.pack('<H', 1) +    # planes
    struct.pack('<H', 24) +   # бит на пиксель
    struct.pack('<I', 0) +    # сжатие
    struct.pack('<I', 8) +    # размер изображения
    struct.pack('<ii', 2835, 2835) +  # разрешение
    struct.pack('<I', 0) +    # цвета
    struct.pack('<I', 0) +    # важные цвета
    b'\x00\x00\xff' +        # RGB: синий пиксель (bytearray)
    b'\x00' * 5              # выравнивание до 4 байт
)
# Извлечение ширины и высоты
(width, height) = struct.unpack('<ii', bmp_bytes[18:26])
print(width, height)  # 1 1
1 1

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

Создание бинарного протокола с контрольной суммой

Пример
import struct
import hashlib

def pack_message(msg_type, payload):
    # msg_type: 1 байт, payload: байты, длина 2 байта
    length = len(payload)
    header = struct.pack('!BH', msg_type, length)
    # CRC32 от заголовка и данных
    crc = struct.pack('!I', zlib.crc32(header + payload) & 0xFFFFFFFF)
    return header + payload + crc

def unpack_message(data):
    msg_type, length = struct.unpack('!BH', data[:3])
    payload = data[3:3+length]
    stored_crc = struct.unpack('!I', data[3+length:3+length+4])[0]
    calc_crc = zlib.crc32(data[:3+length]) & 0xFFFFFFFF
    if stored_crc != calc_crc:
        raise ValueError('Контрольная сумма не совпадает')
    return msg_type, payload

import zlib
packet = pack_message(1, b'Hello')
print(packet.hex())
type_, pay = unpack_message(packet)
print(type_, pay)
0148656c6c6f2f2e6aaf
1 b'Hello'

Здесь создается пакет с типом (1 байт), длиной (2 байта big-endian), данными и CRC32 (4 байта). Распаковка проверяет целостность. Ошибка - неверно вычисленная длина строки или порядок байтов.

Работа с двоичными данными в Python - comments

En
Python двоичные данные (python)