2014-01-19 2 views
5

У меня есть 23 бита, представленные в виде строки, и мне нужно записать эту строку в двоичный файл как 4 байта. Последний байт всегда равен 0. Следующий код работает (Python 3.3), но он не очень элегантен (я довольно новичок в Python и программировании). У вас есть какие-то советы по его улучшению? Кажется, что for-loop может быть полезен, но как сделать резку в цикле без получения IndexError? Обратите внимание, что когда я извлекаю биты в байт, я отменяю бит-порядок.Запись битов в двоичный файл

from array import array 

bin_array = array("B") 
bits = "10111111111111111011110" #Example string. It's always 23 bits 
byte1 = bits[:8][::-1] 
byte2 = bits[8:16][::-1] 
byte3 = bits[16:][::-1] 
bin_array.append(int(byte1, 2)) 
bin_array.append(int(byte2, 2)) 
bin_array.append(int(byte3, 2)) 
bin_array.append(0) 

with open("test.bnr", "wb") as f: 
    f.write(bytes(bin_array)) 

# Writes [253, 255, 61, 0] to the file 

ответ

14

Вы можете рассматривать его как межд, а затем создать 4 байта следующим образом:

>>> bits = "10111111111111111011110" 
>>> int(bits[::-1], 2).to_bytes(4, 'little') 
b'\xfd\xff=\x00' 
+3

+1 Я любил это. Слишком плохо Python2.7 не имеет этой функции –

+0

@Jon Это ... потрясающе. Можно ли пойти другим путем? Что-то вроде: 'int.from_bytes (b '\ xfd \ xff = \ x00', 'little')' и get '" 10111111111111111011110 "' – Olav

+1

@Olav, yup - соответствующим образом его формат: 'format (int.from_bytes (b ' \ xfd \ xff = \ x00 ',' little '),' 023b ') [:: - 1] ' –

1
from array import array 

bin_array = array("B") 
bits = "10111111111111111011110" 

bits = bits + "0" * (32 - len(bits)) # Align bits to 32, i.e. add "0" to tail 
for index in range(0, 32, 8): 
    byte = bits[index:index + 8][::-1] 
    bin_array.append(int(byte, 2)) 

with open("test.bnr", "wb") as f: 
    f.write(bytes(bin_array)) 
3

Модуль struct был разработан именно для такого рода вещи - рассмотреть следующее что преобразование в байты было разбито на некоторые ненужные промежуточные этапы, чтобы сделать его более понятным:

import struct 

bits = "10111111111111111011110" # example string. It's always 23 bits 
int_value = int(bits[::-1], base=2) 
bin_array = struct.pack('i', int_value) 
with open("test.bnr", "wb") as f: 
    f.write(bin_array) 

Более трудный для чтения, но более короткий путь будет:

bits = "10111111111111111011110" # example string. It's always 23 bits 
with open("test.bnr", "wb") as f: 
    f.write(struct.pack('i', int(bits[::-1], 2))) 
1

Вы можете выполнить разделение на одной линии с использованием re.findall метода:

>>>bits = "10111111111111111011110" 
>>>import re 
>>>re.findall(r'\d{1,8}', bits) 
['10111111', '11111111', '1011110'] 

В качестве алгоритма, вы можете подушечка bits по длине 32 а затем использовать re.findall способ сгруппировать его в octects:

>>> bits 
'10111111111111111011110000000000' 
>>> re.findall(r'\d{8}', bits) 
['10111111', '11111111', '10111100', '00000000'] 

Ваш код будет выглядеть так:

import re 
from array import array 

bin_array = array("B") 
bits = "10111111111111111011110".ljust(32, '0') # pad it to length 32 

for octect in re.findall(r'\d{8}', bits): # split it in 4 octects 
    bin_array.append(int(octect[::-1], 2)) # reverse them and append it 

with open("test.bnr", "wb") as f: 
    f.write(bytes(bin_array)) 
+0

Отступ будет более явным как' bits = "10111111111111111011110" .ljust (32,' 0 ') ' –

+0

@JonClements Абсолютно, спасибо за указание! –

Смежные вопросы