2010-09-24 8 views
13

Czy istnieje łatwy sposób, aby odczytać te liczby całkowite w? Wolałbym metodę wbudowaną, ale zakładam, że można to zrobić przy niektórych operacjach bitowych.
CheersJak odczytać liczby całkowite z pliku 24-bitowego i małego endian za pomocą Pythona?

edit
myślałem o innym sposobem, aby to zrobić, że różni się od sposobów poniżej i moim zdaniem jest wyraźniejszy. Na drugim końcu nakłada zerami, a następnie przesuwa wynik. Nie, jeśli jest to wymagane, ponieważ zmienia się wypełnienie dowolną wartością msb.

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

+1 przy edycji. –

Odpowiedz

9

moduł Pythona struct pozwala interpretować bajtów jak różnego rodzaju struktury danych, z kontroli nad endianness.

Jeśli przeczytasz jeden numer trzy-bajtowy z pliku, można przekształcić go w ten sposób:

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

Moduł nie wydaje się, aby wspierać 24-bitowe słowa, stąd '\0' -padding.

EDYCJA: Podpisane liczby są trudniejsze. Można skopiować high-bit, oraz ustawić wysoką trochę do zera, ponieważ porusza się w najwyższym miejscu 4 bajtów (ostatni \xff ma go) .:

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

Albo na python3 (bytes jest zarezerwowana słowo, sprawdzanie bajt tablicy bajtów daje int):

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

Dzięki, ale zapomniałem powiedzieć, że są podpisane, więc dopracowanie najważniejszych bitów nie zadziała, tak samo sprawiedliwe jak moje ograniczone zrozumienie uzupełnienia dwójki idzie. – simonb

+0

@jolly: Odpowiednio poprawiłem swoją odpowiedź. –

+0

Aby poprawić jasność i szybkość, spróbuj '.... jeśli bajty [2] <'\ x80' jeszcze ....' –

7

czy twoje 24-bitowe liczby całkowite ze znakiem lub bez znaku? Bigendian czy littleendian?

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

Podpisany jest trochę bardziej skomplikowane ... uzyskać wartość bez znaku, jak wyżej, to zrobić:

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

Przykro mi kolego, nie widziałem cię tam pod zakładką. Najwyraźniej nie mam wystarczającej reputacji, aby przegłosować, ale dzięki za wysiłek! – simonb

4

Jeśli nie przeszkadza za pomocą zewnętrznej biblioteki wtedy mój moduł bitstring może być pomocne tutaj.

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

Odczytuje to w pierwszych 24 bitach i interpretuje go jako niepodpisaną małą liczbę całkowitą. Po przeczytaniu s.pos ustawiono wartość 24 (położenie bitu w strumieniu), aby można było przeczytać więcej. Na przykład, jeśli chcesz uzyskać listę najbliższych 10 podpisanych liczb można użyć

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

lub jeśli wolisz, możesz po prostu użyć plasterki i właściwości i nie przejmować się czyta:

a = s[0:24].uintle 

Another alternatywą, jeśli masz już 3 bajtów danych od Ciebie plik jest tylko do tworzenia i interpretacji:

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

Wolałbym nie używać biblioteki zewnętrznej dla tego konkretnego projektu, ale mimo to sprawdzę. Jaka jest wydajność podobna do tej? Potencjalnie pojawią się na poziomie około 3 Mb/s, czyli 130 000 na sekundę. Szczerze mówiąc, częstotliwość próbkowania jest znacznie wyższa niż jest to konieczne, więc mogę po prostu odrzucić większość z nich, ale jeśli nie będę zarządzać tą biblioteką? – simonb

+0

@jolly: Jeśli wydajność jest problemem, powinieneś trzymać się metody 'struct'. Bitstring to (na razie) czysty Python, więc nie pokona tego. Jest dość skuteczny, ale nacisk kładzie się na to, aby bitowe zadania były tak proste, jak to tylko możliwe, a nie tak szybkie, jak to możliwe - przynajmniej jeszcze nie :) –

2

trochę późno, ale tutaj jest coś, co może być przydatne w tej sytuacji. Opiera się na zaktualizowanej odpowiedzi OP, ale integruje ją w funkcję, która odczytuje całą listę wartości z spakowanego pliku 24-bitowych znaków. Robi to głównie z struct, więc myślę, że powinien być dość szybki.

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 
Powiązane problemy