web-dev-qa-db-ja.com

ctypesを使用してパックおよびアンパックする方法(構造<-> str)

これはばかげた質問かもしれませんが、ドキュメントやどこにも良い答えが見つかりませんでした。

structを使用してバイナリ構造を定義する場合、構造体にはシリアル化と逆シリアル化(パックとアンパック)の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...
41
Mr Temp

PythonInfo wiki はこれに対する解決策を持っています。

FAQ:ctypes.StructureからPythonにバイトをコピーする方法は?

_def send(self):
    return buffer(self)[:]
_

FAQ: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))のように1行でxy。もちろん、おそらく2番目の引数として、xのリテラルパッキングではなく変数を使用します。

31
Mark Rushakoff

PythonのバイナリI/Oに関するこのリンクをご覧ください。

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

これに基づいて、(ファイルだけでなく)バッファーから読み取るために次のように簡単に書き込むことができます。

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

書くことは簡単です:

g.write(q)

ソケットを使用する場合も同様です。

s.send(q)

そして

s.recv_info(q)

私はpack/unpackとctypesでいくつかのテストを行いましたが、このアプローチはCで直接書くことを除いて最速です

18
Ralph Paul

Python3でテスト済み

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