2009-12-01 13 views
34

To może być głupie pytanie, ale nie mogłem znaleźć dobrej odpowiedzi w dokumentach lub w dowolnym miejscu.Jak pakować i rozpakowywać za pomocą ctypów (Structure <-> str)

Jeśli używam struct zdefiniować strukturę binarną, struct ma 2 symetryczne metody serializacji i deserializacji (pakiet i rozpakować), ale wydaje się, ctypes nie ma prostego sposobu, aby to zrobić. Oto moje rozwiązanie, które jest błędne:

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

który wygląda o prawo do mnie. ctypes nie służy do serializacji, więc fakt, że można to zrobić w 7 liniach kodu, wydaje się całkiem niezły. –

Odpowiedz

25

The PythonInfo wiki ma rozwiązanie tego problemu.

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) 

Ich send jest (bardziej lub mniej) równoważnik pack i receiveSome to swego rodzaju pack_into. Jeśli masz "bezpieczną" sytuację, w której rozpakowujesz się do struktury tego samego typu, co oryginał, możesz je połączyć w jedną linię, tak jak memmove(addressof(y), buffer(x)[:], sizeof(y)), aby skopiować x do . Oczywiście jako drugi argument prawdopodobnie będzie istniała zmienna, a nie literalne opakowanie x.

+1

Przetestowałem to rozwiązanie i działa ono również. Co ważniejsze dla mnie było to, że znalazłeś oficjalny obiekt python.org (FAQ na wiki jest wystarczająco dobry), że hakowanie to jest droga do zrobienia. Wydawało mi się, że te 2 funkcje/metody musiały być gdzieś w ctypes.py już tak hackowanie go za pomocą wskaźników wydawało się bardzo niepythoniczne. Wiem, że niektórzy ludzie twierdzą, że ctypes nie jest zbudowany do serializacji etc, ale lubię ctypes OOP-ness o wiele bardziej niż perl-ish struct module. –

+0

Co powiesz na Python3, który nie ma "bufora"? Jeśli spróbujesz po prostu zastąpić go 'viewview', otrzymasz' TypeError: nieprawidłowe indeksowanie pamięci 0-dim'' –

+0

W Pythonie 3 możesz użyć 'bytes (self)', aby wyodrębnić bajty struktury. – Zanapher

15

Wystarczy popatrzeć na ten link na binarny I/O w Pythonie:

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

Na podstawie tego można po prostu napisać co następuje odczyt z bufora (nie tylko plików):

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

Aby napisać po prostu:

g.write(q) 

to samo za korzystanie soc kets:

s.send(q) 

i

s.recv_info(q) 

Zrobiłem kilka testów z opakowanie/rozpakować i ctypes i takie podejście jest najszybszym z wyjątkiem pisania prosto w C

+5

W wersji 2.6+ bardziej ogólnym "pakietem" jest po prostu 'bytearray (q)', który również wykorzystuje protokół buforowy. Do rozpakowania standardowego 2.6 dodano również na przykład 'Example.from_buffer (buf)' jeśli 'buf' jest zmienne, w przeciwnym razie' Example.from_buffer_copy (buf) '. – eryksun

Powiązane problemy