2010-09-24 6 views
13

¿Hay una manera fácil de leer estos enteros? Preferiría un método integrado, pero supongo que es posible hacerlo con algunas operaciones de bits.
Saludos¿Cómo se pueden leer los enteros de un archivo de 24 bits y poco endian que usan Python?

editar
pensé que de otra manera de hacerlo que es diferente a las maneras abajo y en mi opinión es más clara. Se rellena con ceros en el otro extremo, luego cambia el resultado. No si es necesario porque el cambio se llena con lo que sea que el msb sea inicialmente.

struct.unpack('<i','\0'+ bytes)[0] >> 8 
+1

+1 en su edición. –

Respuesta

9

módulo de Python struct le permite interpretar los bytes como diferentes tipos de estructura de datos, con el control de orden de bytes.

Si se lee un solo número de tres bytes del archivo, se puede convertir de este modo:

struct.unpack('<I', bytes + '\0') 

El módulo no parece apoyar palabras de 24 bits, por lo tanto el Acolchado '\0'.

EDITAR: Los números firmados son más complicados. Se puede copiar la alta bits, y se establece el bit alto a cero porque se mueve al lugar más alto de 4 bytes (el último \xff lo tiene) .:

struct.unpack('<i', bytes + ('\0' if bytes[2] < '\x80' else '\xff')) 

O, para python3 (bytes es una reservados palabra, la comprobación de un byte de una matriz de bytes da una int):

struct.unpack('<i', chunk + ('\0' if chunk[2] < 128 else '\xff')) 
+0

Gracias, pero me olvidé de decir que están firmados, por lo que rellenar los bits más significativos no funcionará, tan justo como mi limitado conocimiento del complemento de dos va. – simonb

+0

@jolly: He modificado mi respuesta en consecuencia. –

+0

Para mayor claridad y velocidad, intente '.... if bytes [2] <'\ x80' else ....' –

7

son sus números enteros de 24 bits con o sin signo? Bigendian o littleendian?

struct.unpack('<I', bytes + '\x00')[0] # unsigned littleendian 
struct.unpack('>I', '\x00' + bytes)[0] # unsigned bigendian 

firmado es un poco más complicado ... obtener el valor sin signo de arriba, luego hacer esto:

signed = unsigned if not (unsigned & 0x800000) else unsigned - 0x1000000 
+0

Lo siento amigo, no te vi allí abajo. Aparentemente, no tengo suficiente reputación para votar, ¡pero gracias por el esfuerzo! – simonb

4

Si no les importa usar una biblioteca externa entonces mi módulo podría ser bitstring útil aquí.

from bitstring import ConstBitStream 
s = ConstBitStream(filename='some_file') 
a = s.read('uintle:24') 

Esto lee en los primeros 24 bits y lo interpreta como un número entero pequeño-endian sin signo. Después de leer s.pos se establece en 24 (la posición del bit en la secuencia), por lo que puede leer más. Por ejemplo, si desea obtener una lista de los próximos 10 enteros con signo que podría utilizar

l = s.readlist('10*intle:24') 

o si lo prefiere, simplemente podría utilizar rebanadas y propiedades y no se moleste con lee:

a = s[0:24].uintle 

Otro alternativa si ya tiene los 3 bytes de datos de archivo se le acaba de crear e interpretar:

a = ConstBitStream(bytes=b'abc').uintle 
+0

Preferiría no utilizar una biblioteca externa para este proyecto en particular, pero lo verificará de todos modos. ¿Cómo es el rendimiento para algo como esto? Es posible que lleguen a alrededor de 3Mb/s, por lo que 130,000 de ellos cada segundo. Francamente, la frecuencia de muestreo es mucho más alta de lo necesario, así que puedo descartar la mayoría de ellos, pero si no lo hago, ¿se administrará esta biblioteca? – simonb

+0

@jolly: si el rendimiento es una preocupación, entonces debes seguir con el método 'struct'. Bitstring es (por ahora) Python puro, por lo que no superará esto. Es razonablemente eficiente, pero el énfasis se ha puesto en hacer que las tareas a nivel de bit sean lo más sencillas posible, no lo más rápido posible, al menos todavía no :) –

2

Un poco tarde, pero aquí hay algo que podría ser útil en esta situación. Se basa en la respuesta actualizada del OP, pero la integra en una función que lee una lista completa de valores de un archivo empaquetado de 24 bits. Lo hace principalmente con struct, así que creo que debería ser razonablemente rápido.

def int24_to_int(self, input_data): 
    bytelen = len(input_data) 
    frames = bytelen/3 
    triads = struct.Struct('3s' * frames) 
    int4byte = struct.Struct('<i') 
    result = [int4byte.unpack('\0' + i)[0] >> 8 for i in triads.unpack(input_data)] 
    return result 
Cuestiones relacionadas