How to read integers from a file that are 24bit and little endian using Python?

ぃ、小莉子 提交于 2019-11-30 22:24:06

问题


Is there an easy way to read these integers in? I'd prefer a built in method, but I assume it is possible to do with some bit operations.
Cheers

edit
I thought of another way to do it that is different to the ways below and in my opinion is clearer. It pads with zeros at the other end, then shifts the result. No if required because shifting fills with whatever the msb is initially.

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

回答1:


Python's struct module lets you interpret bytes as different kinds of data structure, with control over endianness.

If you read a single three-byte number from the file, you can convert it thus:

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

The module doesn't appear to support 24-bit words, hence the '\0'-padding.

EDIT: Signed numbers are trickier. You can copy the high-bit, and set the high bit to zero because it moves to the highest place of 4 bytes (the last \xff has it).:

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

Or, for python3 (bytes is a reserved word, checking a byte of a byte array gives an int):

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



回答2:


Are your 24-bit integers signed or unsigned? Bigendian or littleendian?

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

Signed is a little more complicated ... get the unsigned value as above, then do this:

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



回答3:


If you don't mind using an external library then my bitstring module could be helpful here.

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

This reads in the first 24 bits and interprets it as an unsigned little-endian integer. After the read s.pos is set to 24 (the bit position in the stream), so you can then read more. For example if you wanted to get a list of the next 10 signed integers you could use

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

or if you prefer you could just use slices and properties and not bother with reads:

a = s[0:24].uintle

Another alternative if you already have the 3 bytes of data from you file is just to create and interpret:

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



回答4:


A bit late, but here's something that could be useful in this situation. It builds on the OP's updated answer, but integrates it into a function that reads out a whole list of values from a packed file of 24 bit ints. It does it mostly with struct, so I think it should be reasonably fast.

  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


来源:https://stackoverflow.com/questions/3783677/how-to-read-integers-from-a-file-that-are-24bit-and-little-endian-using-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!