Как читать целые числа из файла, который является 24-битным и маленьким, с использованием Python?

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

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

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

Ответы

Ответ 1

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

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

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

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

EDIT: Подписанные номера сложнее. Вы можете скопировать high-bit и установить высокий бит в ноль, потому что он перемещается на самое высокое место в 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'))

Ответ 2

Являются ли ваши 24-битные целые числа подписанными или неподписанными? Bigendian или littleendian?

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

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

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

Ответ 3

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

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

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

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

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

a = s[0:24].uintle

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

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

Ответ 4

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

  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