Cómo empacar y desempacar usando ctypes (Estructura < - > str)
Pregunta
Esta podría ser una pregunta tonta, pero no pude encontrar una buena respuesta en los documentos ni en ningún otro lugar.
Si uso struct para definir una estructura binaria, la estructura tiene 2 métodos simétricos para la serialización y deserialización (empacar y desempaquetar) pero parece que ctypes no tiene Una forma sencilla de hacer esto. Aquí está mi solución, que se siente mal:
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...
Solución
El wiki de PythonInfo tiene una solución para esto.
Preguntas frecuentes: ¿Cómo copio bytes a Python desde ctypes.Structure?
def send(self): return buffer(self)[:]
Preguntas frecuentes: ¿Cómo copio bytes a una estructura ctypes.Structure desde Python?
def receiveSome(self, bytes): fit = min(len(bytes), ctypes.sizeof(self)) ctypes.memmove(ctypes.addressof(self), bytes, fit)
Su send
es el equivalente (más o menos) de pack
, y ReceiveSome
es una especie de pack_into . Si tiene una "caja fuerte" situación en la que está desempacando en una estructura del mismo tipo que la original, puede alinearla en una línea como
memmove (addressof (y), buffer (x) [:], sizeof (y))
para copiar x
en y
. Por supuesto, probablemente tendrá una variable como segundo argumento, en lugar de un paquete literal de x
.
Otros consejos
Eche un vistazo a este enlace en E / S binaria en python:
http://www.dabeaz.com /blog/2009/08/python-binary-io-handling.html
Basado en esto, simplemente puede escribir lo siguiente para leer desde un búfer (no solo archivos):
g = open("foo","rb")
q = Example()
g.readinto(q)
Escribir es simplemente:
g.write(q)
Lo mismo para usar sockets:
s.send(q)
y
s.recv_info(q)
Hice algunas pruebas con pack / unpack y ctypes y este enfoque es el más rápido, excepto para escribir directamente en C
Probado en Python3
e = Example(12, 13)
serialized = bytes(e)
deserialized = Example.from_buffer_copy(serialized)