Запутался в байтах в Python - PullRequest
       17

Запутался в байтах в Python

1 голос
/ 11 февраля 2012

Я недавно приступил к анализу двоичных данных с помощью Python, но меня смущает то, как "байтовые" элементы обрабатываются Python.Возьмем, к примеру, следующий разговор интерпретатора:

>>> f = open('somefile.gz', 'rb')
>>> f
<open file 'textfile.gz', mode 'rb' at 0xb77f4d88>
>>> bytes = f.read()
>>> bytes[0]
'\x1f'
>>> len(bytes[0])
1
>>> int(bytes[0])  <---- calling __str__ automatically on bytes[0] ?
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '\x1f'

В приведенном выше сеансе показано, что размер байта [0] равен 1 байту, а представление __str__ - шестнадцатеричное.Не беспокойтесь, но когда я пытаюсь трактовать байты [0] как один байт, я получаю странное поведение.

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

Например, будет "первые два байта \xbeef, следующий - десятичное 8, за которым следует упакованное битовое поле, где каждый из8 битов байта представляют некоторый флаг? Я ​​полагаю, что есть несколько модулей, облегчающих эту задачу, но я бы хотел сделать это с нуля.

Я видел ссылки на модуль struct, нонет ли способа проверить байты, прочитанные напрямую, без введения нового модуля? Что-то вроде bytes[0] == 0xbeef?

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

Ответы [ 2 ]

5 голосов
/ 11 февраля 2012

Вы используете Python 2.x.До Python 3.0 чтение файла, даже двоичного, возвращает строку.То, что вы называете «байтовым» объектом, на самом деле является строкой.Индексирование в строку, как вы делаете с помощью «bytes [0]», просто возвращает 1-символьную строку.

Модуль struct, вероятно, лучше всего подходит для того, что вы хотите, но вы можете делать то, что просите, без негоесли вы действительно хотите:

"Что-то вроде байтов [0] == 0xbeef?"

Это не будет работать, потому что 0xbeef - это двухбайтовая последовательность, но байты [0]только один байт.Вместо этого вы можете сделать это:

bytes[0:2] == b'\xbe\xef'

В Python 3.x все работает немного лучше, чем вы ожидаете.Чтение двоичного файла возвращает объект bytes, который ведет себя как последовательность 1-байтовых целых чисел без знака, а не как строка.

2 голосов
/ 11 февраля 2012

Если вы хотите проанализировать двоичные данные, проверьте модуль struct .Вот пример из документа:

>>> from struct import *
>>> pack('hhl', 1, 2, 3)
'\x00\x01\x00\x02\x00\x00\x00\x03'
>>> unpack('hhl', '\x00\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
>>> calcsize('hhl')
8

Узнайте больше о unpack:)

Итак, если вы хотите прочитать первые 2 байта в виде короткого знака без знака и выполнить тестс 0xbeef:

struct.unpack('H', bytes[0:2]) == 0xbeef
...