2010-04-05 25 views

risposta

24

Leggere i bit da un file, prima i bit bassi.

def bits(f): 
    bytes = (ord(b) for b in f.read()) 
    for b in bytes: 
     for i in xrange(8): 
      yield (b >> i) & 1 

for b in bits(open('binary-file.bin', 'r')): 
    print b 
+0

Testato questo (btw il byte è little endian) e ord ('\ x04') restituisce 4 che dovrebbe restituire la stringa di bit '0000100' usando il tuo codice ottengo '000100000' – David

+0

oops volevo dire ottenere '00100000' con il tuo codice – David

+1

Dà prima i bit più bassi (che è naturale, dato che fornisce anche i byte bassi). Ma se vuoi l'altro ordine, puoi cambiare 'xrange (8)' in 'invertito (xrange (8))'. –

18

L'unità più piccola con cui è possibile lavorare è un byte. Per lavorare a livello di bit è necessario utilizzare bitwise operators.

x = 3 
#Check if the 1st bit is set: 
x&1 != 0 
#Returns True 

#Check if the 2nd bit is set: 
x&2 != 0 
#Returns True 

#Check if the 3rd bit is set: 
x&4 != 0 
#Returns False 
+2

Ti spiace aggiungere ulteriori informazioni, dal momento che l'OP sembra chiaramente un principiante? –

+0

Certo, vengo da uno sfondo matlab e non riesco a trovare un codice di tipo 'ubit1' per python. Ho usato il seguente: f = open ('filename', 'rb') var = f.read (1) che restituisce var come stringa di valore esadecimale '\ x04' come ottengo il binario rappresentazione della stringa? – David

+0

@David: Vedo, già coperto dalla risposta accettata. –

10

Non sarà possibile leggere ogni bit uno per uno - è necessario leggerlo byte per byte. Si può facilmente estrarre i bit fuori, però:

f = open("myfile", 'rb') 
# read one byte 
byte = f.read(1) 
# convert the byte to an integer representation 
byte = ord(byte) 
# now convert to string of 1s and 0s 
byte = bin(byte)[2:].rjust(8, '0') 
# now byte contains a string with 0s and 1s 
for bit in byte: 
    print bit 
+0

provato e per l'esempio in cui byte = '\ 0x04' il codice di cui sopra restituisce \t '0b' – David

+0

@ David OOPS! Lascia che ti aggiusti. Scusate .... (modifica) Ok, ora è riparato. Dovrebbe funzionare. –

+0

Grazie ora il tuo codice dà byte = 100 che è la rappresentazione di base 2 corretta di ord ('\ 0x04') = 4 ma il byte letto non deve essere '00000100' – David

2

Ci sono due possibili modi per restituire il bit i-esimo di un byte. Il "primo bit" potrebbe riferirsi al bit di ordine elevato o potrebbe riferirsi al bit di ordine inferiore.

Ecco una funzione che accetta una stringa e un indice come parametri e restituisce il valore del bit in quella posizione. Come scritto, tratta il bit di ordine basso come il primo bit. Se si desidera innanzitutto il bit di ordine superiore, è sufficiente decommentare la riga indicata.

def bit_from_string(string, index): 
     i, j = divmod(index, 8) 

     # Uncomment this if you want the high-order bit first 
     # j = 8 - j 

     if ord(string[i]) & (1 << j): 
       return 1 
     else: 
       return 0 

L'indicizzazione inizia da 0. Se si desidera che l'indicizzazione per iniziare a 1, è possibile regolare indice in funzione prima di chiamare divmod.

Esempio Utilizzo:

>>> for i in range(8): 
>>>  print i, bit_from_string('\x04', i) 
0 0 
1 0 
2 1 
3 0 
4 0 
5 0 
6 0 
7 0 

Ora, per come funziona:

Una stringa è composto di byte di 8 bit, quindi prima usiamo divmod() per rompere l'indice in a parti:

  • i: l'indice del byte corretto all'interno della stringa
  • j: l'indice del bit corretta w ntro che byte

Usiamo la funzione ord() per convertire il carattere string[i] in un tipo intero. Quindi, (1 << j) calcola il valore del bit j-th spostando a sinistra 1 per j. Infine, usiamo bit per bit e per testare se quel bit è impostato. In tal caso, restituire 1, altrimenti restituire 0.

+0

grazie per il dettaglio nel tuo commento ho guardato gli operatori del cambio di bit, ma non sono riuscito a vedere come ha funzionato per questo.La tua risposta aiuta a chiarire gli operatori bit a bit e l'approccio. Grazie – David

+0

Daniel grazie per la soluzione generale sopra. – David

0

Questo è piuttosto veloce penserei:

import itertools 
data = range(10) 
format = "{:0>8b}".format 
newdata = (False if n == '0' else True for n in itertools.chain.from_iterable(map(format, data))) 
print(newdata) # prints tons of True and False 
0

si Supponendo avere un file chiamato bloom_filter.bin che c mantiene una serie di bit e si desidera leggere l'intero file e utilizzare tali bit in un array.

Innanzitutto creare la matrice in cui saranno memorizzati i bit dopo aver letto,

from bitarray import bitarray 
a=bitarray(size)   #same as the number of bits in the file 

Aprire il file, utilizzando aperto o con, tutto è bene ... Mi attengo con aperto qui,

f=open('bloom_filter.bin','rb') 

Ora caricare tutti i bit nella matrice 'un' in un solo colpo utilizzando,

f.readinto(a) 

'a' è ora un bitarray contenente tutti i bit

+0

devi installare prima il modulo bitarray: pip install bitarray – vac

4

Per leggere un byte da un file: bytestring = open(filename, 'rb').read(1). Nota: il file viene aperto nella modalità binaria.

Per ottenere bit, convertire il bytestring in un numero intero: byte = bytestring[0] (Python 3) o byte = ord(bytestring[0]) (Python 2) ed estrarre la punta desiderata: (byte >> i) & 1:

>>> for i in range(8): (b'a'[0] >> i) & 1 
... 
1 
0 
0 
0 
0 
1 
1 
0 
>>> bin(b'a'[0]) 
'0b1100001' 
2

Unire alcune delle risposte precedenti userei :

[int(i) for i in "{0:08b}".format(byte)] 

Per ogni byte letto dal file. I risultati per un esempio di byte 0x88 sono:

>>> [int(i) for i in "{0:08b}".format(0x88)] 
[1, 0, 0, 0, 1, 0, 0, 0] 

È possibile assegnarlo a una variabile e lavorare come da richiesta iniziale. "{0.08}" garantisce la lunghezza totale dei byte