2010-09-24 11 views
13

C'è un modo semplice per leggere questi numeri interi? Preferirei un metodo integrato, ma presumo che sia possibile fare con alcune operazioni di bit.
AcclamazioniCome leggere gli interi da un file che è 24 bit e little endian usando Python?

modificare
ho pensato di un altro modo per farlo che è diversa per i modi di seguito e, a mio parere è più chiaro. Si riempie di zeri all'altra estremità, quindi sposta il risultato. No, se richiesto, poiché lo spostamento si riempie con qualunque sia inizialmente il msb.

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

+1 sulla modifica. –

risposta

9

modulo di Python struct consente di interpretare byte come i diversi tipi di struttura dei dati, con il controllo su endianness.

Se si legge un singolo numero tre byte dal file, è possibile convertire così:

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

Il modulo non sembra supportare le parole a 24 bit, da cui il '\0' -padding.

MODIFICA: i numeri firmati sono più complicati. È possibile copiare il-bit alto, e impostare il bit alto a zero perché si muove al posto più alto di 4 byte (l'ultimo \xff ha) .:

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

Oppure, per python3 (bytes è una riservata parola, controllando un byte di un array di byte dà un int):

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

Grazie, ma ho dimenticato di dire che sono firmati in modo da riempire i bit più significativi non funzionerà, giusto come la mia comprensione limitata del complemento a due va. – simonb

+0

@jolly: Ho modificato di conseguenza la mia risposta. –

+0

Per maggiore chiarezza e velocità, prova '.... se byte [2] <'\ x80' altro ....' –

7

Sono i tuoi numeri interi a 24 bit con o senza segno? Bigendiano o littleendiano?

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

firmato è un po 'più complicato ... ottenere il valore senza segno come sopra, quindi fare questo:

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

Scusami amico, non ti ho visto lì sotto l'angolo. A quanto pare non ho abbastanza reputazione per alzare la voce, ma grazie per lo sforzo! – simonb

4

Se non ti dispiace utilizzando una libreria esterna, allora il mio modulo bitstring potrebbe essere utile qui.

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

Questo legge nei primi 24 bit e lo interpreta come un intero little-endian senza segno. Dopo la lettura, s.pos è impostato su 24 (la posizione del bit nel flusso), quindi è possibile leggerne altre. Per esempio, se si voleva ottenere una lista dei prossimi 10 interi con segno si potrebbe usare

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

o se si preferisce si può solo usare le fette e le proprietà e non perdere tempo con legge:

a = s[0:24].uintle 

altro alternativa se hai già i 3 byte di dati da voi file è solo per creare e interpretare:

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

Preferirei non utilizzare una libreria esterna per questo particolare progetto, ma lo controllerò comunque. Come sono le prestazioni per qualcosa di simile? Potrebbero arrivare a circa 3 Mb/s, quindi 130.000 al secondo. Sinceramente la frequenza di campionamento è molto più alta del necessario, quindi posso semplicemente scartarne la maggioranza, ma se non lo faccio gestirò questa libreria? – simonb

+0

@jolly: se le prestazioni sono un problema, è necessario attenersi al metodo 'struct'. Bitstring è (per ora) puro Python, quindi non batterà questo. È ragionevolmente efficiente, ma l'enfasi è stata posta sul rendere le attività bit a bit il più semplici possibile, non il più veloce possibile - almeno non ancora :) –

2

un po 'tardi, ma qui c'è qualcosa che potrebbe essere utile in questa situazione. Si basa sulla risposta aggiornata dell'OP, ma la integra in una funzione che legge un intero elenco di valori da un file compresso di 24 bit int. Lo fa per lo più con struct, quindi penso che dovrebbe essere abbastanza veloce.

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