2010-04-05 24 views
28

Tengo un archivo donde el primer byte contiene información codificada. En Matlab puedo leer el byte bit a bit con var = fread(file, 8, 'ubit1'), y luego recuperar cada bit por var(1), var(2), etc.Usando Python ¿Cómo puedo leer los bits en un byte?

¿Hay algún lector de bits equivalente en python?

Respuesta

24

Lea los bits de un archivo, primero los bits bajos.

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

Probado esto (por cierto, el byte es little endian) y ord ('\ x04') devuelve 4 que debe devolver la cadena de bits '0000100' usando tu código Obtengo '000100000' – David

+0

Vaya, quiero decir que recibí '00100000' con tu código – David

+1

Da primero bits bajos (lo cual es natural, ya que también da bytes bajos primero). Pero si quiere el otro orden, puede cambiar 'xrange (8)' a 'reverseed (xrange (8))'. –

18

La unidad más pequeña con la que podrá trabajar es un byte. Para trabajar en el nivel de bit, necesita usar 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

¿Le importa agregar más información, ya que el OP parece claramente un principiante? –

+0

Claro que vengo de un fondo de matlab y no puedo encontrar un tipo de código 'ubit1' para python. He utilizado lo siguiente: f = abrir ('nombre de archivo', 'rb') var = f.read (1) que devuelve var como el valor hexadecimal string '\ x04' cómo obtengo el binario representación de la cadena? – David

+0

@David: Ya veo, ya cubierto por la respuesta aceptada. –

10

Usted no será capaz de leer cada bit uno por uno - usted tiene que leer byte a byte. Se puede extraer fácilmente los bits a cabo, sin embargo:

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

probé y para el ejemplo en el que byte = '\ 0x04' el código anterior devuelve \t '0b' – David

+0

@ David OOPS! Déjame arreglar eso. Lo siento ... (Editar) Bien, ahora está arreglado. Deberia trabajar. –

+0

Gracias su código ahora da byte = 100 que es la representación base correcta 2 de ord ('\ 0x04') = 4 pero no debería ser el byte leído '00000100' – David

2

Hay dos maneras posibles para devolver el i-ésimo bit de un byte. El "primer bit" podría referirse al bit de orden superior o podría referirse al bit de orden inferior.

Aquí hay una función que toma una cadena e índice como parámetros y devuelve el valor del bit en esa ubicación. Como está escrito, trata el bit de orden bajo como el primer bit. Si quiere primero el bit de orden alto, simplemente elimine el comentario de la línea indicada.

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 

La indexación comienza en 0. Si desea que la indexación para empezar a 1, se puede ajustar el índice de la función antes de llamar divmod.

Ejemplo de uso:

>>> 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 

Ahora, por como funciona:

Una cadena se compone de bytes de 8 bits, por lo que primero usamos DIVMOD() para romper el índice en a partes:

  • i: el índice del byte correcta dentro de la cadena
  • j: el índice de la broca correcta w entro de ese byte

Utilizamos la función ord() para convertir el carácter en string[i] en un tipo entero. Luego, (1 << j) calcula el valor del bit j-ésimo por desplazamiento a la izquierda 1 por j. Finalmente, usamos bitwise-y para probar si ese bit está configurado. Si es así, devuelva 1; de lo contrario, devuelva 0.

+0

¡Entendido! Gracias por los detalles en su comentario. Miré a los operadores de cambio de bit, pero no pude ver cómo funcionó para esto.Su respuesta ayuda a aclarar los operadores bit a bit y el enfoque. Gracias – David

+0

Daniel gracias por la solución general anterior. – David

0

Esto es bastante rápido yo creo:

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

que Suponiendo tener un archivo llamado bloom_filter.bin que c contiene una matriz de bits y desea leer todo el archivo y usar esos bits en una matriz.

En primer lugar crear la matriz en la que se almacenan los bits después de leer,

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

Abrir el archivo, usando abierto o con, cualquier cosa está bien ... estoy pegando con abierta aquí,

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

Ahora carga todos los bits en la matriz 'a' en una sola toma utilizando,

f.readinto(a) 

'a' ahora es un bitarray que contiene todos los bits

+0

primero tiene que instalar el módulo bitarray: pip install bitarray – vac

4

Para leer un byte de un archivo: bytestring = open(filename, 'rb').read(1). Nota: el archivo se abre en el modo binario.

Para obtener los bits, convertir la cadena de bytes en un entero: byte = bytestring[0] (Python 3) o byte = ord(bytestring[0]) (Python 2) y extraer los bits deseada: (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

unirse a algunas de las respuestas anteriores Me gustaría utilizar :

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

Por cada byte leído del archivo. Los resultados para un ejemplo de bytes 0x88 es:

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

puede asignarla a una variable y trabajar según su petición inicial. El "{0.08}" es para garantizar la longitud total del byte

Cuestiones relacionadas