2016-03-30 21 views
5

Dato un file con dati binari compressi per la risoluzione, vorrei convertire i bit sub-byte nelle loro rappresentazioni integer in python. Con questo voglio dire che ho bisogno di interpretare n bit da un file come numero intero.Il modo più veloce per decomprimere i bit (sotto byte) dei numeri dal file

Attualmente sto leggendo il file negli oggetti bitarray e sto convertendo sottoinsiemi degli oggetti in numeri interi. Il processo funziona ma è abbastanza lento e macchinoso. C'è un modo migliore per farlo, forse con il modulo struct?

import bitarray 

bits = bitarray.bitarray() 
with open('/dir/to/any/file.dat','r') as f: 
    bits.fromfile(f,2) # read 2 bytes into the bitarray 

    ## bits 0:4 represent a field 
    field1 = int(bits[0:4].to01(), 2) # Converts to a string of 0s and 1s, then int()s the string 

    ## bits 5:7 represent a field 
    field2 = int(bits[4:7].to01(), 2) 

    ## bits 8:16 represent a field 
    field3 = int(bits[7:16].to01(), 2) 

print """All bits: {bits}\n\tfield1: {b1}={field1}\n\tfield2: {b2}={field2}\n\tfield3: {b3}={field3}""".format(
     bits=bits, b1=bits[0:4].to01(), field1=field1, 
     b2=bits[4:7].to01(), field2=field2, 
     b3=bits[7:16].to01(), field3=field3) 

Uscite:

All bits: bitarray('0000100110000000') 
    field1: 0000=0 
    field2: 100=4 
    field3: 110000000=384 
+0

Le dimensioni del campo si ripetono mentre si passa attraverso il file o sono completamente casuali? Attraversano i confini dei byte? –

+0

1. I campi attraversano i contorni dei byte. 2. I campi si ripetono, ma c'è un chunk di dimensioni sconosciute che deve essere letto dinamicamente. OSSIA nel mio esempio, puoi dire che 'field3' mi dice quanto deve essere grande' field4'. Quindi il file ripete 'field1',' field2' ecc. –

+0

è la dimensione di field4 in byte o bit? Dev'essere tutto in un numero intero? – TisteAndii

risposta

2

Questo dovrebbe funzionare per il vostro caso specifico:

#bitmasks of fields 1-3, they fit in 2 bytes 
FIELD1 = 0b1111000000000000 # first 4 bits 
FIELD2 = 0b0000111000000000 # next 3 bits 
FIELD3 = 0b0000000111111111 # last 9 bits 

def bytes_to_int(num): #convert bytes object to an int 
    res = 0 
    num = num[::-1] # reverse the bytes 
    for i in range(len(num)): 
     res += num[i] * (256**i) 
    return res 

def get_fields(f): 
    chunk = bytes_to_int(f.read(2)) # read 2 bytes, f1-f3, convert to int 
    f1 = (chunk & FIELD1) >> 12 # get each field with its bitmask 
    f2 = (chunk & FIELD2) >> 9 
    f3 = chunk & FIELD3 
    f4 = f.read(f3) # field4 as a bytes object 
    f4 = bytes_to_int(f4) #comment this line if you want field4 as a bytes obj 

    return f1, f2, f3, f4 

file = open('file.dat','rb') 

#using your sample data 
print(get_fields(file)) # returns 0, 4, 384, field4 as an int 

file.close() 

avrebbe potuto usare il modulo struct, ma cant decomprimere più di 8 byte in un int, che sarà necessario per la vostra Campo4 che è lunga 384 byte .

+0

Buona menzione per 'int.from_bytes'. Sfortunatamente sto eseguendo 2.7. Questo è quello che sto cercando anche se –

+0

@ zachd1_618 ok ... posso correggere che ... stai leggendo il file come testo o nel formato byte grezzo? Se è solo 1 e 0 come testo, allora int (n, 2) può eseguire la conversione. Inoltre è corretto dire che dal momento che field4 è in byte e non attraversa i confini dei byte, solo i campi 1-3 sono a livello di sotto-byte e sono tutti contenuti in 2 byte? – TisteAndii

+0

Sto leggendo il file in byte non elaborati. Come il tuo esempio con 'file.read (num_bytes)'. E sì, è corretto dire che la dimensione sconosciuta 'field4' è in interi byte e non attraversa i confini dei byte. –

4

Se siete ok con utilizzando il modulo di qualcuno, sembra che il modulo bitstring ha una buona rappresentazione e manipolazione di bit: http://pythonhosted.org/bitstring/index.html

Per esempio, se si sa la dimensione dei tuoi campi puoi utilizzare le stringhe di formato: http://pythonhosted.org/bitstring/reading.html#reading-using-format-strings

import bitstring 
bitstream = bitstring.ConstBitStream(filename='testfile.bin') 
field1, field2, field3 = bitstream.readlist('int:4, int:3, int:9') 
.210

Se non conoscete i vostri campi di taglie si poteva leggere in tutti i bit e quindi utilizzare affettare per estrarre tutti i campi: http://pythonhosted.org/bitstring/slicing.html

import bitstring 
bitstream = bitstring.ConstBitStream(filename='testfile.bin') 
bits = bitstring.BitArray(bitstream) 
field1 = bits[0:4].int 
field2 = bits[4:7].int 
field3 = bits[7:16].int 

Solo un pensiero, probabilmente già trovato questo modulo.

+0

Oh e se si desidera utilizzare l'uso non firmato anziché firmato uint – pmartin

Problemi correlati