Конвертировать байты в биты в Python - PullRequest
20 голосов
/ 11 января 2012

Я работаю с Python3.2. Мне нужно взять шестнадцатеричный поток в качестве входных данных и проанализировать его на уровне битов. Поэтому я использовал

bytes.fromhex(input_str)

для преобразования строки в фактические байты. Теперь, как мне преобразовать эти байты в биты?

Ответы [ 9 ]

31 голосов
/ 11 января 2012

Другой способ сделать это - использовать модуль bitstring:

>>> from bitstring import BitArray
>>> input_str = '0xff'
>>> c = BitArray(hex=input_str)
>>> c.bin
'0b11111111'

А если вам нужно лишить ведущего 0b:

>>> c.bin[2:]
'11111111'

Модуль bitstring не является обязательным, как показывает ответ jcollado , но у него есть множество эффективных методов преобразования ввода в биты и манипулирования ими. Вы можете найти это удобно (или нет), например:

>>> c.uint
255
>>> c.invert()
>>> c.bin[2:]
'00000000'

и т.д.

20 голосов
/ 11 января 2012

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

Если вы хотите только биты 7 и 8, используйте, например,

val = (byte >> 6) & 3

(это: сдвинуть байт на 6 бит вправо - отбросить их. Затем сохранить только последние два бита 3 - это число с установленными первыми двумя битами ...)

Их можно легко перевести в простые операции с ЦП, которые очень быстрые.

18 голосов
/ 11 января 2012

Как насчет этого?

>>> bin(int('ff', base=16))
'0b11111111'

Это преобразует шестнадцатеричную строку, которую вы имеете, в целое число, а это целое число - в строку, в которой каждый байт имеет значение 0/1, в зависимости от значения в битах целого числа.

Как указано в комментарии, если вам нужно избавиться от префикса 0b, вы можете сделать это следующим образом:

>>> bin(int('ff', base=16)).lstrip('0b')
11111111

или так:

>>> bin(int('ff', base=16))[2:]
11111111
7 голосов
/ 11 января 2012

в двоичный:

bin(byte)[2:].zfill(8)
4 голосов
/ 11 мая 2015

Я думаю, что самым простым было бы использовать numpy здесь.Например, вы можете прочитать файл в байтах, а затем легко развернуть его до битов, например:

Bytes = numpy.fromfile(filename, dtype = "uint8")
Bits = numpy.unpackbits(Bytes)
2 голосов
/ 29 августа 2017

Используйте ord при чтении байтов чтения:

byte_binary = bin(ord(f.read(1))) # Add [2:] to remove the "0b" prefix

Или

Использование str.format():

'{:08b}'.format(ord(f.read(1)))
1 голос
/ 14 июля 2018

с использованием Python синтаксис строки формата

>>> mybyte = bytes.fromhex("0F") # create my byte using a hex string
>>> binary_string = "{:08b}".format(int(mybyte.hex(),16))
>>> print(binary_string)
00001111

Во второй строке происходит волшебство. Все байтовые объекты имеют функцию .hex(), которая возвращает шестнадцатеричную строку. Используя эту шестнадцатеричную строку, мы преобразуем ее в целое число, сообщая функции int(), что это строка с основанием 16 (потому что шестнадцатеричное значение - это основание 16). Затем мы применяем форматирование к этому целому числу, чтобы оно отображалось в виде двоичной строки. {:08b} - это место, где происходит настоящее волшебство. Используется мини-язык Спецификация формата format_spec. В частности, он использует части width и type синтаксиса format_spec. 8 устанавливает width в 8, как мы получаем хороший 0000, а b устанавливает тип в двоичный.

Я предпочитаю этот метод, а не bin(), потому что использование строки формата дает большую гибкость.

0 голосов
/ 21 ноября 2017

Другие ответы здесь предоставляют биты в порядке big-endian ('\x01' становится '00000001')

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

def bits_little_endian_from_bytes(s):
    return ''.join(bin(ord(x))[2:].rjust(8,'0')[::-1] for x in s)

А для другого направления:

def bytes_from_bits_little_endian(s):
    return ''.join(chr(int(s[i:i+8][::-1], 2)) for i in range(0, len(s), 8))
0 голосов
/ 26 сентября 2017

Вот как это сделать, используя format()

print "bin_signedDate : ", ''.join(format(x, '08b') for x in bytevector)

Важно 08b . Это означает, что для завершения байта будет добавлено максимум 8 начальных нулей. Если вы не укажете это, формат будет иметь переменную длину в битах для каждого преобразованного байта.

...