Scopo | Converte tra stringhe e dati binari |
Versione Python | 1.4 e successiva |
A partire dal 1 gennaio 2021 le versioni 2.x di Python non sono piu' supportate. Ti invito a consultare la corrispondente versione 3.x dell'articolo per il modulo struct
Il modulo struct include le funzioni per la conversione tra stringhe di byte e tipi di dati nativi di Python come numeri e stringhe.
Ci sono un insieme di funzioni a livello modulo per lavorare con valori strutturati, e c'è anche la classe Struct (nuova in Python 2.5). Gli specificatori di formato sono convertiti dal loro formato stringa ad una rappresentazione compilata, simile al modo in cui sono compilate le espressioni regolari. La conversione richiede delle risorse, quindi in genere è più efficiente farlo una volta sola quando si crea l'istanza di Struct, quindi chiamare i metodi dell'istanza invece che usare le funzioni a livello modulo. Tutti gli esempi seguenti usano la classe Struct.
Struct supporta il packing di dati in stringhe e l' unpacking di dati dalle stringhe usando specificatori di formattazione costituiti da caratteri che rappresentano il tipo di dati ed indicatori di conteggio ed endian-ness opzionali. Per un completo dettaglio fare riferimento alla documentazione della libreria standard .
In questo esempio lo specificatore di formato richiede un valore intero o long, una stringa di due caratteri ed un numero a virgola mobile. Gli spazi tra gli specificatori di formato sono qui inclusi per chiarezza, e sono ignorati quando la formattazione viene compilata.
import struct
import binascii
values = (1, 'ab', 2.7)
s = struct.Struct('I 2s f')
packed_data = s.pack(*values)
print 'Valori originali :', values
print 'Stringa formattazione:', s.format
print 'Usa :', s.size, 'byte'
print 'Valore Packed :', binascii.hexlify(packed_data)
$ python example_pack.py Valori originali : (1, 'ab', 2.7000000000000002) Stringa formattazione: I 2s f Usa : 12 byte Valore Packed : 0100000061620000cdcc2c40
Il valore packed viene convertito in una sequenza di byte in notazione esadecimale per la stampa, visto che alcuni dei caratteri sono null.
Se si passa il valore packed ad
unpack()
, riotteniamo di fatto gli stessi valori originali (notare la discrepanza nel valore a virgola mobile).
import struct
import binascii
packed_data = binascii.unhexlify('0100000061620000cdcc2c40')
s = struct.Struct('I 2s f')
unpacked_data = s.unpack(packed_data)
print 'Valori Unpacked:', unpacked_data
$ python example_unpack.py Valori Unpacked: (1, 'ab', 2.7000000476837158)
Nel modo predefinito i valori sono codificati usando la nozione nativa della libreria di "endianness". E' semplice sovrascrivere quella scelta fornendo una direttiva esplicita di endianness nella stringa di formattazione.
import struct
import binascii
values = (1, 'ab', 2.7)
print 'Valori originali:', values
endianness = [
('@', 'native, native'),
('=', 'native, standard'),
('<', 'little-endian'),
('>', 'big-endian'),
('!', 'network'),
]
for code, name in endianness:
s = struct.Struct(code + ' I 2s f')
packed_data = s.pack(*values)
print
print 'Formato stringa :', s.format, 'per', name
print 'Usa :', s.size, 'byte'
print 'Valore Packed :', binascii.hexlify(packed_data)
print 'Valore Unpacked :', s.unpack(packed_data)
$ python struct_endianness.py Valori originali: (1, 'ab', 2.7000000000000002) Formato stringa: @ I 2s f per native, native Usa : 12 byte Valore packed : 0100000061620000cdcc2c40 Valore unpacked: (1, 'ab', 2.7000000476837158) Formato stringa: = I 2s f per native, standard Usa : 10 byte Valore packed : 010000006162cdcc2c40 Valore unpacked: (1, 'ab', 2.7000000476837158) Formato stringa: < I 2s f per little-endian Usa : 10 byte Valore packed : 010000006162cdcc2c40 Valore unpacked: (1, 'ab', 2.7000000476837158) Formato stringa: > I 2s f per big-endian Usa : 10 byte Valore packed : 000000016162402ccccd Valore unpacked: (1, 'ab', 2.7000000476837158) Formato stringa: ! I 2s f per network Usa : 10 byte Valore packed : 000000016162402ccccd Valore unpacked: (1, 'ab', 2.7000000476837158)
Il lavorare con dati binari packed è in genere riservato per situazioni delicate ad alte prestazioni o per il passaggio di dati da/per moduli estensione. Un modo di ottimizzare è di evitare di allocare un nuovo buffer per ogni struttura packed. I metodi
pack_into()
e
unpack_from()
forniscono il supporto alla scrittura diretta a buffer pre-allocati.
import struct
import binascii
s = struct.Struct('I 2s f')
values = (1, 'ab', 2.7)
print 'Originali:', values
print
print 'buffer stringa ctypes'
import ctypes
b = ctypes.create_string_buffer(s.size)
print 'Prima :', binascii.hexlify(b.raw)
s.pack_into(b, 0, *values)
print 'Dopo :', binascii.hexlify(b.raw)
print 'Unpacked:', s.unpack_from(b, 0)
print
print 'array'
import array
a = array.array('c', '\0' * s.size)
print 'Prima :', binascii.hexlify(a)
s.pack_into(a, 0, *values)
print 'Dopo :', binascii.hexlify(a)
print 'Unpacked:', s.unpack_from(a, 0)
Vedere anche:
Vedere anche: