Используя символ b в аргументе режима функции open, вы получаете возможность открывать двоичные файлы с данными платформонезависимым способом, а также читать и записывать их содержимое с помощью обычных методов объекта файла. Но как обрабатывать двоичные данные после того, как они будут прочитаны? Эти данные будут возвращены сценарию в виде простой строки байтов, большая часть из которых наверняка будет соответствовать непечатаемым символам.
Если нужно лишь переписать двоичные данные в другой файл или передать другой программе, тогда все просто — достаточно записать строку байтов в другой файл, открытый в двоичном режиме. Если потребуется извлечь некоторое количество байтов из определенной позиции, можно воспользоваться операцией извлечения среза строки. При необходимости можно даже использовать битовые операции. Кроме того, имеется мощный инструмент, позволяющий получить двоичные данные в структурированном виде или сконструировать их, — модуль struct из стандартной библиотеки.
В модуле struct имеются функции для упаковывания и распаковывания двоичных данных, как если бы данные были созданы с помощью объявления struct языка C. Имеется возможность при упаковывании и распаковывании данных учитывать прямой или обратный порядок следования байтов (порядок следования байтов определяет, где будут находиться старшие значимые биты в двоичном представлении чисел, — слева или справа). Создание двоичного файла с данными, например, — достаточно простая задача: нужно упаковать значения языка Python в строку байтов и записать ее в файл. Строка формата в вызове pack ниже определяет: прямой порядок следования байтов (>), целое число, 4-символьную строку, короткое целое число и вещественное число:
>>> import struct
>>> data = struct.pack(‘>i4shf’, 2, ‘spam’, 3, 1.234)
>>> data
b’\x00\x00\x00\x02spam\x00\x03?\x9d\xf3\xb6’
>>> file = open(‘data.bin’, ‘wb’)
>>> file.write(data)
14
Обратите внимание, что модуль struct возвращает строку байтов: сейчас мы находимся в царстве двоичных данных, а не текста, и для сохранения должны использовать двоичные файлы. Как обычно, интерпретатор отображает большую часть байтов с упакованными двоичными данными, которые не соответствуют печатаемым символам, в виде шестнадцатеричных экранированных последовательностей \xNN. Чтобы выполнить обратное преобразование этих данных, нужно прочитать их из файла и передать модулю struct с той же строкой формата, как и при создании, — в результате получится кортеж значений, полученных в результате анализа строки байтов и преобразованных в объекты языка Python:
>>> import struct
>>> file = open(‘data.bin’, ‘rb’)
>>> data = file.read()
>>> values = struct.unpack(‘>i4shf’, data)
>>> values
(2, b’spam’, 3, 1.2339999675750732)
Анализируемые строки — это также строки байтов, и к ним допускается применять строковые и битовые операции для более глубокого анализа:
> >> bin(values[0] | 0b1) # доступ к битам и байтам
‘0b11’
> >> values[1], list(values[1]), values[1][0]
(b’spam’, [115, 112, 97, 109], 115)
Обратите также внимание, что здесь может пригодиться операция извлечения среза. 4-символьную строку из середины только что прочитанных упакованных двоичных данных легко получить, используя операцию извлечения среза. Числовые значения также можно извлекать подобным способом и передавать функции struct.unpack для преобразования:
> >> data
b’\x00\x00\x00\x02spam\x00\x03?\x9d\xf3\xb6’
> >> data[4:8] b’spam’
>>> number = data[8:10]
>>> number b’\x00\x03’
>>> struct.unpack(‘>h’, number)
(3,)
Упакованные двоичные данные бывают получены из самых разных контекстов, включая некоторые виды сетевых взаимодействий и представление данных другими языками программирования. Однако все это не относится к разряду повседневных задач программирования, поэтому оставим описание подробностей за разделом с описанием модуля struct в руководстве по стандартной библиотеке Python.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011