2009-12-01 20 views
34

Esto podría ser una pregunta tonta pero no pude encontrar una buena respuesta en los documentos o en cualquier lugar.Cómo empacar y desempaquetar usando ctypes (Estructura <-> str)

Si uso estructura para definir una estructura binaria, la estructura tiene 2 métodos simétricos para la serialización y deserialización (y deshacer) pero parece 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... 
+2

Eso se ve bastante bien para mí. ctypes no es para serialización, por lo que el hecho de que puedas hacerlo en 7 líneas de código parece bastante bueno en realidad. –

Respuesta

25

The PythonInfo wiki tiene una solución para esto.

FAQ: How do I copy bytes to Python from a ctypes.Structure?

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

FAQ: How do I copy bytes to a ctypes.Structure from Python?

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

Su send es el (más o menos) equivalente a pack y receiveSome es una especie de pack_into. Si tiene una situación "segura" en la que está desempacando en una estructura del mismo tipo que el original, puede alinearla como memmove(addressof(y), buffer(x)[:], sizeof(y)) para copiar x en y. Por supuesto, es probable que tenga una variable como segundo argumento, en lugar de un embalaje literal de x.

+1

He probado esta solución y funciona también. Lo que era más importante para mí fue que encontraste una entidad oficial de python.org (las preguntas frecuentes en la wiki son lo suficientemente buenas) afirman que piratearlas es el camino a seguir. Simplemente sentí como si estas 2 funciones/métodos tuvieran que estar en alguna parte en ctypes.py, así que piratearlo usando punteros parecía muy antiponético. Sé que algunas personas dicen que los ctypes no están diseñados para la serialización, etc., pero me gusta mucho más que los módulos OOP-ness mucho más que el módulo de estructura perl-ish. –

+0

¿Qué hay de Python3 que no tiene 'buffer'? Si intenta simplemente reemplazarlo por 'memoryview', obtendrá' TypeError: indexación no válida de 0-dim memory' –

+0

En Python3 puede usar 'bytes (self)' para extraer los bytes de estructura. – Zanapher

15

Tener un vistazo a este enlace en binario I/O en Python:

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

Con base en esto, simplemente hay que escribir lo siguiente para leer desde una memoria intermedia (no sólo archivos):

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

para escribir es simplemente:

g.write(q) 

Lo mismo para el uso de soc TFE:

s.send(q) 

y

s.recv_info(q) 

hice algunas pruebas con el paquete/desempaquetar y ctypes y este enfoque es el más rápido, excepto para escribir directamente en C

+5

En 2.6+, un 'paquete 'más genérico es simplemente' bytearray (q) ', que también usa el protocolo de buffer. Para el desempaquetado genérico 2.6 también se agrega, por ejemplo, 'Example.from_buffer (buf)' si 'buf' es mutable, sino' Example.from_buffer_copy (buf) '. – eryksun

Cuestiones relacionadas