2014-01-19 13 views
5

Ich habe 23 Bits als String dargestellt, und ich muss diese Zeichenfolge in eine Binärdatei als 4 Bytes schreiben. Das letzte Byte ist immer 0. Der folgende Code funktioniert (Python 3.3), aber er fühlt sich nicht sehr elegant an (ich bin ziemlich neu in Python und Programmierung). Hast du irgendwelche Tipps, um es besser zu machen? Es scheint, dass eine For-Schleife nützlich sein könnte, aber wie mache ich das Slicing innerhalb der Schleife, ohne einen IndexError zu bekommen? Beachten Sie, dass, wenn ich die Bits in ein Byte extrahiere, ich die Bit-Reihenfolge umkehre.Schreiben von Bits in eine Binärdatei

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 

Antwort

14

Sie können es als int behandeln, dann erstellen Sie die 4 Bytes wie folgt:

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

+1 Ich liebte das. Schade, Python2.7 hat dieses Feature nicht –

+0

@ Jon Das ist ... erstaunlich. Ist es möglich, in die andere Richtung zu gehen? So etwas wie: 'int.from_bytes (b '\ xfd \ xff = \ x00', 'little')' und hole '" 10111111111111111011110 "' – Olav

+1

@Olav, yup - formatiere es passend: '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

Das struct Modul für genau diese Art der Sache entworfen wurde - betrachten Sie das folgende in die die Umwandlung zu Bytes hat nach unten in einige unnötige Zwischenschritte gebrochen zu machen, das Verständnis klarer:

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) 

Ein schwerer zu lesen, aber kürzerer Weg wäre:

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

Sie können die Spaltung in einer Linie mit re.findall Methode ausführen:

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

Als Algorithmus, können Sie Pad bits auf Länge 32 und verwenden sie dann re.findall Methode zur Gruppe es in Oktette:

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

Ihr Code so sein würde:

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

Die Auffüllung wäre expliziter als' bits = "10111111111111111011110" .ljust (32,' 0 ') ' –

+0

@ JonClements Absolut, danke fürs Hinweisen! –

Verwandte Themen