Wpis z mikrobloga

Mam w pliku binarnym zmultipleksowane dane (załóżmy, że każda litera to 2 bajty, dane to konkretnie int16):

ABCD ABCD ABCD
Jak wczytać w Pythonie tylko co któreś 2 bajty (tzn. w przykładzie tylko dane litery, np. tylko A)?
Jedyne co na razie wymyśliłem to:
zrobić sobie pustego stringa
file.read() - żeby przeczytać bajt i go dodać do tego stringa
file.seek() - żeby przesunąć się na kolejną pozycję

i na końcu użyć numpy.fromstring()
Da się to zrobić jakoś wydajniej? Albo chociaż ładniej?

#python #programowanie
  • 7
@Lempek: Jeżeli nie boli cię pamięć, to możesz chyba zrobić coś w rodzaju [byte for i, byte in enumerate(file.read()) if i % 5 < 2]. Oczywiście wyrażenie na końcu trzeba odpowiednio dostroić, no i w ten sposób dostajesz tablicę pojedynczych bajtów, a nie po 2, więc dalej trzeba to jakoś przetworzyć, ale w każdym razie pozbywasz się brzydkiej pętli - przynajmniej chwilowo. Jak będę miał pomysł, jak to rozwinąć w
@Lempek: Wyszedł mi najpierw taki potwór:

bytes = file.read()
[(byte1, byte2) for i, byte1, byte2 in zip(range(len(bytes)), bytes, bytes[1:]) if i % 4 == 0]

Niewydajne i obleśne, ale w jednym wyrażeniu :P

Natomiast sensownym rozwiązaniem może być to, zwięzłe i chyba czytelne:

numpy.fromstring(file.read(), dtype=numpy.int16)[::4]
@Lempek: To możliwe, że trzeba plik wczytywać w kawałkach, cały może się w RAMie nie mieścić.

Drugą wersję można próbować przyspieszyć, omijając konwersję niepotrzebnych danych, ale jeżeli fromstring jest dobrze zoptymalizowane, to to wcale nie musi specjalnie pomóc - w sumie nie jest całkiem wykluczone, że to co napisałem jest bliskie optimum.
@Lempek: jeśli plik jest duży najlepiej napisać pętlę (albo generator) czytającą jakiś chunk (np. 4096 bajtów) i parsować dane w locie, z uwzględnieniem "ciekawych przypadków", czyli np. fragmentów interesującego ciągu leżących na złączeniu dwóch chunków.