2009-12-01 88 views
34

這可能是一個愚蠢的問題,但我無法在文檔或任何地方找到好的答案。如何使用ctypes打包和解包(結構<-> str)

如果我使用結構定義一個二元結構,該結構具有系列化和反序列化2層對稱的方法(包並解壓),但它似乎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... 
+2

這看起來對我的權利直寫最快的。 ctypes不是用於序列化的,所以你可以在7行代碼中做到這一點,事實上它確實很不錯。 – 2009-12-01 12:17:00

回答

25

The PythonInfo wiki有一個解決方案。

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) 

send他們是的pack的(更多或更少)等效,和receiveSome是排序一個pack_into的。如果你有一個「安全」的情況,你打開一個與原來相同類型的結構,你可以像memmove(addressof(y), buffer(x)[:], sizeof(y))一樣將x複製到y。當然,你可能會有一個變量作爲第二個參數,而不是x的文字包裝。

+1

我測試了這個解決方案,它也可以工作。對我來說更重要的是,你發現一個官方的python.org實體(維基中的FAQ很好)聲稱黑客是它的走向。我只是覺得這兩個函數/方法已經在ctypes.py的某個地方了,所以使用指針來攻擊它看起來非常和諧。我知道有些人說ctypes不是爲序列化等而構建的,但我喜歡ctypes OOP-ness比perl-ish結構模塊多得多。 – 2009-12-01 18:06:14

+0

Python3沒有'buffer'呢?如果你試圖簡單地用'memoryview'替換它,你會得到'TypeError:0-dim內存的無效索引' – 2017-02-28 15:39:04

+0

在Python3中,你可以使用'bytes(self)'來提取結構字節。 – Zanapher 2017-05-12 14:19:53

15

看一看二進制這個鏈接的I/O的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) 

同樣使用SOC凱茨:

s.send(q) 

s.recv_info(q) 

我做了一些測試與包裝/解包和ctypes的這種做法,除了在C

+5

在2.6+中,更通用的'pack'只是'bytearray(q)',它也使用緩衝協議。對於通用的拆包2.6也添加了,例如'Example.from_buffer(buf)'如果'buf'是可變的,否則'Example.from_buffer_copy(buf)'。 – eryksun 2013-07-16 14:24:53