Как читать целые числа из файла с 24-битным и байтовым порядком байтов с использованием Python? - PullRequest
13 голосов
/ 24 сентября 2010

Есть ли простой способ прочитать эти целые числа в?Я бы предпочел встроенный метод, но я предполагаю, что это возможно сделать с некоторыми битовыми операциями.
Cheers

edit
Я думал о другом способе сделать этоэто отличается от способов ниже и, на мой взгляд, более понятно.Он дополняется нулями на другом конце, затем сдвигает результат.Нет, если требуется, потому что смещение заполняется тем, что изначально было в msb.

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

Ответы [ 4 ]

12 голосов
/ 24 сентября 2010

Модуль Python struct позволяет интерпретировать байты как различные типы структуры данных с контролем над порядком байтов.

Если вы прочитали одно трехбайтовое число из файла, вы можете преобразовать его следующим образом:

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

Модуль не поддерживает 24-битные слова, поэтому '\0' -padding.

РЕДАКТИРОВАТЬ: подписанные номера сложнее. Вы можете скопировать старший бит и установить старший бит на ноль, потому что он перемещается на самое старшее место из 4 байтов (последний \xff имеет его).:

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

Или для python3 (bytes - зарезервированное слово, проверка байта массива байтов дает int):

struct.unpack('<i', chunk + ('\0' if chunk[2] < 128 else '\xff'))
7 голосов
/ 24 сентября 2010

Ваши 24-битные целые числа подписаны или не подписаны? Бигендан или Литтлдиан?

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

Signed немного сложнее ... получите значение без знака, как указано выше, затем сделайте следующее:

signed = unsigned if not (unsigned & 0x800000) else unsigned - 0x1000000
4 голосов
/ 24 сентября 2010

Если вы не возражаете против использования внешней библиотеки, мой модуль bitstring может быть полезен здесь.

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

Это читает первые 24 бита и интерпретирует его как беззнаковое целое число с прямым порядком байтов. После чтения s.pos устанавливается в 24 (битовая позиция в потоке), поэтому вы можете читать больше. Например, если вы хотите получить список из следующих 10 целых чисел со знаком, вы можете использовать

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

или, если вы предпочитаете, вы можете просто использовать кусочки и свойства и не беспокоиться о чтениях:

a = s[0:24].uintle

Другая альтернатива, если у вас уже есть 3 байта данных из вашего файла, это просто создать и интерпретировать:

a = ConstBitStream(bytes=b'abc').uintle
2 голосов
/ 25 мая 2014

Немного поздно, но вот кое-что, что может быть полезно в этой ситуации.Он основан на обновленном ответе OP, но интегрирует его в функцию, которая считывает весь список значений из упакованного файла с 24-битными значениями.Это делается в основном с помощью struct, поэтому я думаю, что это должно быть достаточно быстро.

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