Come comprimere e decomprimere utilizzando ctypes (Struttura <-> str)

Questa potrebbe essere una domanda stupida ma io non riuscivo a trovare una buona risposta nei documenti o in qualsiasi luogo.

Se io uso struct per definire una struttura binaria, la struttura dispone di 2 simmetrico metodi per la serializzazione e la deserializzazione (pack e unpack) ma sembra ctypes non dispone di un modo semplice per fare questo. Ecco la mia soluzione, che si sente male:

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...
  • Che sembra sul punto giusto per me. ctypes non è per la serializzazione, quindi il fatto che si può fare in 7 righe di codice sembra abbastanza buono in realtà.
InformationsquelleAutor Mr Temp | 2009-12-01



3 Replies
  1. 30

    Il PythonInfo wiki ha una soluzione per questo.

    FAQ: Come faccio copia byte per Python da un ctypes.La struttura?

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

    FAQ: Come faccio copia byte per un ctypes.Struttura da Python?

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

    Loro send è (più o meno) equivalente di pack, e receiveSome è una sorta di pack_into. Se si dispone di una “cassetta di sicurezza” situazione in cui sei disimballaggio in una struttura dello stesso tipo di quello originale, è possibile una riga come memmove(addressof(y), buffer(x)[:], sizeof(y)) per copiare x in y. Naturalmente, probabilmente hanno una variabile come secondo argomento, piuttosto che un valore letterale di imballaggio di x.

    • Ho provato questa soluzione e funziona così. Che cosa è più importante per me è che hai trovato un ufficiale python.org entità (FAQ del wiki è abbastanza buono) stato di hacking è la strada da percorrere. Mi sentivo come se queste 2 funzioni/metodi doveva essere da qualche parte in ctypes.py già così hacking utilizzando puntatori sembrava molto unpythonic. So che alcune persone dicono ctypes non è costruito per la serializzazione ecc, ma mi piace il ctypes OOP-ness molto di più rispetto al perl-ish struct module.
    • Che cosa circa Python3 che non hanno buffer? Se si tenta di sostituire semplicemente con memoryview, si otterrà TypeError: invalid indexing of 0-dim memory
    • In Python3 è possibile utilizzare bytes(self) per estrarre la struttura byte.
  2. 18

    Dare un’occhiata a questo link sul binario di i/o in python:

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

    Sulla base di questo si può semplicemente scrivere la seguente per leggere da un buffer (non solo i file):

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

    Di scrivere è semplicemente:

    g.write(q)

    Lo stesso per il tramite socket:

    s.send(q)

    e

    s.recv_info(q)

    Ho fatto alcuni test con pack/decomprimere e ctypes e questo approccio è il più veloce, tranne per la scrittura dritto in C

    • 2.6+, un più generico pack è solo bytearray(q), che utilizza anche il buffer di protocollo. Per la decompressione generica 2.6 aggiunto anche, per esempio, Example.from_buffer(buf) se buf è mutevole, altro Example.from_buffer_copy(buf).
  3. 4

    Testato su Python3

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

Lascia un commento