struct - Strutture Dati Binari
Scopo: Converte tra stringhe e dati binari
Il modulo struct include funzioni per la conversione tra stringhe di byte e tipi dati nativi di Python come numeri e stringhe.
Funzioni Contro la Classe Struct
E' disponibile per lavorare con valori strutturati sia un insieme di funzioni a livello di modulo che la classe Struct
. Gli specificatori di formato sono convertiti dal loro formato stringa in una rappresentazione compilata, simile al modo nel quale sono gestite le espressioni regolari. La conversione richiede qualche risorsa, quindi è tipicamente più efficiente farlo una sola volta quando si crea l'istanza di Struct
, poi chiamare i metodi sull'istanza invece che usare le funzioni a livello di modulo. Tutti gli esempi che seguono utilizzano la classe Struct
.
Impacchettare e Spacchettare
Le struttura supportano l'impacchettamento dei dati in stringhe, e lo spacchettamento di dati da stringhe usando specificatori di formato composti da caratteri che rappresentano il tipo di dato e indicatori opzionali di contatori ed endianness. Si faccia riferimento alla documentazione della libreria standard per un elenco completo degli specificatori di formato supportati.
In questo esempio, lo specificatore chiama un valore intero o intero lungo, una stringa di due byte e un numero a virgola mobile. Gli spazi nello specificatore di formato sono inclusi per separare gli indicatori di tipo, e vengono ignorati quanto il formato viene compilato.
# struct_pack.py
import struct
import binascii
values = (1, 'ab'.encode('utf-8'), 2.7)
s = struct.Struct('I 2s f')
packed_data = s.pack(*values)
print('Valori originali :', values)
print('Formato stringa :', s.format)
print('Usa :', s.size, 'byte')
print('Valore impacchettato:', binascii.hexlify(packed_data))
Questo esempio converte il valore impacchettato in una sequenza di byte esadecimali per la stampa con binascii.hexlify
, visto che alcuni caratteri sono null.
$ python3 struct_pack.py Valori originali : (1, b'ab', 2.7) Formato stringa : I 2s f Usa : 12 byte Valore impacchettato: b'0100000061620000cdcc2c40'
Si usi unpack()
per estrarre dati dalla loro rappresentazione impacchettata.
# struct_unpack.py
import struct
import binascii
packed_data = binascii.unhexlify(b'0100000061620000cdcc2c40')
s = struct.Struct('I 2s f')
unpacked_data = s.unpack(packed_data)
print('Valori spacchettati:', unpacked_data)
In pratica, passando il valore impacchettato a unpack()
vengono restituiti gli stessi valori (si noti la discrepanza nel valore a virgola mobile).
$ python3 struct_unpack.py Valori spacchettati: (1, b'ab', 2.700000047683716)
Endianness
Nella modalità predefinita, i valori sono codificati usando la nozione di endianness della libreria C nativa. E' facile annullare questa scelta fornendo una direttiva di endianness esplicita nella stringa di formato.
# struct_endianness.py
import struct
import binascii
values = (1, 'ab'.encode('utf-8'), 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 impacchettato:', binascii.hexlify(packed_data))
print('Valore spacchettato :', s.unpack(packed_data))
La tabella qui sotto elenca gli specificatori di ordine dei byte usati da Struct
.
CODICE | SIGNIFICATO |
---|---|
@ | Ordine nativo |
= | Standard nativo |
< | little-endian |
> | big-endian |
! | Ordine network |
$ python3 struct_endianness.py Valori originali : (1, b'ab', 2.7) Formato stringa : @ I 2s f per native, native Usa : 12 byte Valore impacchettato: b'0100000061620000cdcc2c40' Valore spacchettato : (1, b'ab', 2.700000047683716) Formato stringa : = I 2s f per native, standard Usa : 10 byte Valore impacchettato: b'010000006162cdcc2c40' Valore spacchettato : (1, b'ab', 2.700000047683716) Formato stringa : < I 2s f per little-endian Usa : 10 byte Valore impacchettato: b'010000006162cdcc2c40' Valore spacchettato : (1, b'ab', 2.700000047683716) Formato stringa : > I 2s f per big-endian Usa : 10 byte Valore impacchettato: b'000000016162402ccccd' Valore spacchettato : (1, b'ab', 2.700000047683716) Formato stringa : ! I 2s f per network Usa : 10 byte Valore impacchettato: b'000000016162402ccccd' Valore spacchettato : (1, b'ab', 2.700000047683716)
Buffer
Il lavoro con dati binari impacchettati è tipicamente riservato per situazioni sensibili alle prestazioni o per passare dati da/per moduli di estensione. In questi casi è possibile eseguire una ottimizzazione evitando il sovraccarico dell'allocazione di un nuovo buffer per ogni struttura impacchettata. I metodi pack_into()
e unpack_from()
supportano la scrittura diretta verso buffer pre allocati.
# struct_buffers.py
import array
import binascii
import ctypes
import struct
s = struct.Struct('I 2s f')
values = (1, 'ab'.encode('utf-8'), 2.7)
print('Originale :', values)
print()
print('buffer stringhe ctype')
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('Spacchettati:', s.unpack_from(b, 0))
print()
print('array')
a = array.array('b', b'\0' * s.size)
print('Prima :', binascii.hexlify(a))
s.pack_into(a, 0, *values)
print('Dopo :', binascii.hexlify(a))
print('Spacchettati:', s.unpack_from(a, 0))
L'attributo size
di Struct
mostra quanto grande deve essere il buffer.
$ python3 struct_buffers.py Originale : (1, b'ab', 2.7) buffer stringhe ctype Prima : b'000000000000000000000000' Dopo : b'0100000061620000cdcc2c40' Spacchettati: (1, b'ab', 2.700000047683716) array Prima : b'000000000000000000000000' Dopo : b'0100000061620000cdcc2c40' Spacchettati: (1, b'ab', 2.700000047683716)
Vedere anche:
- struct
- La documentazione della libreria standard per questo modulo.
- Note di portabilità per questo modulo
- array
- Il modulo
array
è per lavorare con sequenze di valori di tipo prefissato. - binascii
- Il modulo
binascii
produce rappresentazioni ASCII di dati binari - Endiannes (Wikipedia)
- Spiegazione dell'ordine dei byte ed endianness nella codifica.