将4个字节转换为BigEndianStructure,而不先转换为uint32

时间:2014-11-10 17:33:49

标签: python python-3.x ctypes

我将以4个字节存储的日期和时间转换为Python格式。我先想出天真的做法。然后我尝试使用ctypes所以它应该更快:

from ctypes import *
from datetime import datetime


def bit_unpack(data, bits):
    value = int.from_bytes(data, "big")
    unpacked = []
    for i, field in enumerate(bits):
        shift = sum(bits[i+1:])
        mask = 2 ** field - 1
        bit_field = (value >> shift) & mask
        unpacked.append(bit_field)
    return unpacked


def to_date(data):
    y, m, d, h, n, s = bit_unpack(data, (6, 4, 5, 5, 6, 6))
    return datetime(1980 + y, m, d, h, n, s)


class PackedDate(BigEndianStructure):
    _fields_ = [
        ("year", c_uint, 6),
        ("month", c_uint, 4),
        ("day", c_uint, 5),
        ("hours", c_uint, 5),
        ("minutes", c_uint, 6),
        ("seconds", c_uint, 6),
    ]


class Transfer(Union):
    _fields_ = [
        ("bytes", c_uint32),
        ("date", PackedDate),
    ]


def to_date2(data):
    transfer = Transfer()   
    transfer.bytes = int.from_bytes(data, "little")
    date = transfer.date
    return datetime(date.year + 1980, date.month, date.day, date.hours, date.minutes, date.seconds)


if __name__ == "__main__":
    byte_data = b'q\xa6\xb1\xdf'
    print(to_date(byte_data))
    print(to_date2(byte_data))

    import timeit
    print(timeit.timeit("to_date(byte_data)", r"from bitunpack import to_date; byte_data = b'q\xa6\xb1\xdf'"))
    print(timeit.timeit("to_date2(byte_data)", r"from bitunpack import to_date2; byte_data = b'q\xa6\xb1\xdf'"))

然而,我不喜欢的是这部分:

transfer.bytes = int.from_bytes(data, "little")

我将4个字节转换为uint32。我可以更改我的联盟,以便能够更容易地接受4字节数组而不首先将其转换为uint32吗?我尝试了c_ubyte * 4,但获得了TypeError: expected c_ubyte_Array_4 instance, got bytes

1 个答案:

答案 0 :(得分:0)

您可以使用所有ctypes类型上提供的from_buffer_copy方法直接从PackedDate数据创建bytes对象:

>>> date = PackedDate.from_buffer_copy(data)
>>> datetime(date.year + 1980, date.month, date.day, date.hours, date.minutes, date.seconds)
datetime.datetime(2008, 6, 19, 11, 7, 31)