如何使用ctypes进行打包和解包(结构体 <-> 字符串)

49 投票
4 回答
36744 浏览
提问于 2025-04-15 16:33

这可能是个傻问题,但我在文档里或者其他地方找不到好的答案。

如果我用struct来定义一个二进制结构,这个结构有两个对称的方法来进行序列化和反序列化(分别叫做打包和解包),但是ctypes似乎没有简单的方法来做到这一点。以下是我的解决方案,但我觉得这样做不太对:

from ctypes import *

class Example(Structure):
    _fields_ = [
        ("index", c_int),
        ("counter", c_int),
        ]

def Pack(ctype_instance):
    buf = string_at(byref(ctype_instance), sizeof(ctype_instance))
    return buf

def Unpack(ctype, buf):
    cstring = create_string_buffer(buf)
    ctype_instance = cast(pointer(cstring), POINTER(ctype)).contents
    return ctype_instance

if __name__ == "__main__":
    e = Example(12, 13)
    buf = Pack(e)
    e2 = Unpack(Example, buf)
    assert(e.index == e2.index)
    assert(e.counter == e2.counter)
    # note: for some reason e == e2 is False...

4 个回答

13

在Python3上进行了测试

e = Example(12, 13)
serialized = bytes(e)
deserialized = Example.from_buffer_copy(serialized)
19

你可以看看这个关于Python中二进制输入输出的链接:

http://www.dabeaz.com/blog/2009/08/python-binary-io-handling.html

根据这个链接,你可以简单地写下面的代码来从一个缓冲区读取数据(不仅仅是文件):

g = open("foo","rb")
q = Example()
g.readinto(q)

写入数据也很简单:

g.write(q)

使用套接字(socket)也是一样的:

s.send(q)

还有

s.recv_into(q)

我用pack/unpack和ctypes做了一些测试,这种方法是最快的,除了直接用C语言写的。

36

PythonInfo wiki上有这个问题的解决方案。

常见问题:我怎么把字节复制到Python中的ctypes.Structure里?

def send(self):
    return buffer(self)[:]

常见问题:我怎么从Python把字节复制到ctypes.Structure里?

def receiveSome(self, bytes):
    fit = min(len(bytes), ctypes.sizeof(self))
    ctypes.memmove(ctypes.addressof(self), bytes, fit)

他们的 send 函数大致相当于 pack,而 receiveSome 则有点像 pack_into。如果你在一个“安全”的情况下,也就是说你要解包的结构体和原来的类型是一样的,你可以用一行代码像这样 memmove(addressof(y), buffer(x)[:], sizeof(y)) 来把 x 复制到 y 里。当然,第二个参数你可能会用一个变量,而不是直接写 x 的值。

撰写回答