Как читать целые числа из файла, который является 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