io — flussi di input/output

Questo modulo contiene tipi aggiuntivi di oggetti stream (simili a file) e funzioni di supporto. Espone la funzione builtin open() insieme a buffer di testo e binari in memoria (StringIO, BytesIO) che implementano l’interfaccia stream standard read/write/seek.

Gerarchia concettuale

Differenze rispetto a CPython

La gerarchia concettuale delle classi base degli stream è semplificata in MicroPython, come descritto in questa sezione.

Le classi base (astratte) degli stream, che fungono da fondamento per il comportamento di tutte le classi concrete, in CPython aderiscono ad alcune dicotomie (classificazioni a coppie). In MicroPython sono in qualche modo semplificate e rese implicite per ottenere maggiore efficienza e risparmiare risorse.

Un’importante dicotomia in CPython è quella tra stream con e senza buffer. In MicroPython, attualmente tutti gli stream sono privi di buffer. Questo perché tutti i sistemi operativi moderni, e perfino molti RTOS e driver di filesystem, eseguono già il buffering dalla loro parte. Aggiungere un ulteriore livello di buffering è controproducente (un problema noto come «bufferbloat») e occupa memoria preziosa. Si noti che esistono comunque casi in cui il buffering può essere utile, quindi potremmo introdurre il supporto opzionale al buffering in un secondo momento.

Ma in CPython un’altra importante dicotomia è legata alla «presenza di buffer»: se uno stream può incorrere o meno in letture/scritture parziali. Una lettura parziale si verifica quando un utente chiede ad esempio 10 byte da uno stream ma ne ottiene di meno, e analogamente per le scritture. In CPython, gli stream senza buffer sono automaticamente soggetti a operazioni parziali, mentre quelli con buffer ne sono garantiti immuni. L’assenza di letture/scritture parziali è una caratteristica importante, poiché consente di sviluppare programmi più concisi ed efficienti, qualcosa di altamente auspicabile per MicroPython. Pertanto, sebbene MicroPython non supporti gli stream con buffer, fornisce comunque stream senza operazioni parziali. Se ci saranno operazioni parziali o meno dipende dalle esigenze di ciascuna classe specifica, ma si raccomanda vivamente agli sviluppatori di privilegiare il comportamento senza operazioni parziali per i motivi sopra esposti. Ad esempio, i socket di MicroPython sono garantiti contro letture/scritture parziali. In realtà, al momento non esiste alcun esempio di classe stream con operazioni parziali nel core, e una tale classe sarebbe specifica per un particolare hardware.

Il comportamento senza operazioni parziali diventa complicato nel caso di stream non bloccanti, dato che il comportamento bloccante rispetto a quello non bloccante è un’altra dicotomia di CPython, pienamente supportata da MicroPython. Gli stream non bloccanti non attendono mai che i dati arrivino o vengano scritti: leggono/scrivono tutto ciò che è possibile, oppure segnalano la mancanza di dati (o la capacità di scrivere dati). Chiaramente, ciò è in conflitto con la politica di «assenza di operazioni parziali», e in effetti il caso degli stream non bloccanti con buffer (e quindi senza operazioni parziali) è intricato in CPython: in alcuni casi tale combinazione è vietata, in altri non è definita o semplicemente non documentata, in alcuni casi solleva eccezioni verbose. La questione è molto più semplice in MicroPython: gli stream non bloccanti sono importanti per operazioni asincrone efficienti, quindi questa proprietà prevale su quella dell“«assenza di operazioni parziali». Pertanto, mentre gli stream bloccanti evitano le letture/scritture parziali ogni volta che è possibile (l’unico caso per ottenere una lettura parziale è il raggiungimento della fine del file, oppure in caso di errore (ma gli errori non restituiscono dati parziali, bensì sollevano eccezioni)), gli stream non bloccanti possono produrre dati parziali per evitare di bloccare l’operazione.

L’ultima dicotomia è quella tra stream binari e di testo. MicroPython li supporta naturalmente, ma mentre in CPython gli stream di testo sono intrinsecamente dotati di buffer, in MicroPython non lo sono. (In effetti, questo è uno dei casi per cui potremmo introdurre il supporto al buffering.)

Si noti che, per motivi di efficienza, MicroPython non fornisce classi base astratte corrispondenti alla gerarchia sopra descritta, e non è possibile implementare, o derivare per sottoclasse, una classe stream in puro Python.

Funzioni

io.open(name: str, mode: str = 'r', **kwargs) Any

Apre un file. La funzione builtin open() è un alias di questa funzione. Il parametro mode è sempre supportato; il supporto per altri argomenti può variare.

Classi

class io.IOBase

Classe base per gli oggetti stream («simili a file»). Le sottoclassi concrete implementano i metodi di I/O di basso livello seguenti (readinto, write, ioctl); il runtime costruisce su di essi il protocollo stream di più alto livello (read, readline, readlines, close, iterazione), così ogni istanza di stream supporta tali metodi anche quando la sottoclasse non li definisce.

Metodi di implementazione (sovrascrivili in una sottoclasse):

readinto(buf: bytearray) int | None

Legge byte nel buffer scrivibile buf. Restituisce il numero di byte letti, 0 alla fine dello stream, oppure None se al momento non sono disponibili dati (per uno stream non bloccante).

write(buf: bytes) int | None

Scrive i byte in buf. Restituisce il numero di byte scritti, oppure None se la scrittura non può essere eseguita al momento (per uno stream non bloccante).

ioctl(request: int, arg: int) int

Controlla lo stream/dispositivo sottostante. request è uno dei codici di richiesta MP_STREAM_*. Restituisce un valore non negativo in caso di successo, oppure un valore errno negativo in caso di errore.

Metodi del protocollo stream (disponibili su ogni istanza di stream):

read(size: int = -1)

Legge e restituisce fino a size byte (o caratteri, in modalità testo). Se size è omesso o negativo, legge fino alla fine dello stream. Restituisce bytes per gli stream binari e str per gli stream di testo; un risultato vuoto indica la fine dello stream.

readline(size: int = -1)

Legge e restituisce una riga, incluso il carattere di newline finale se presente. Se viene fornito size, vengono letti al massimo size byte (o caratteri). Restituisce un bytes / str vuoto alla fine dello stream.

readlines() list

Legge fino alla fine dello stream e restituisce una list di righe, ciascuna con il proprio newline finale.

close() None

Chiude lo stream e rilascia eventuali risorse sottostanti. Le operazioni su uno stream chiuso sollevano OSError (oppure ValueError per gli stream in memoria).

seek(offset: int, whence: int = 0) int

Cambia la posizione corrente dello stream a offset byte rispetto a whence (0 = inizio dello stream, 1 = posizione corrente, 2 = fine dello stream). Restituisce la nuova posizione assoluta. Solleva OSError su uno stream non posizionabile.

tell() int

Restituisce la posizione assoluta corrente nello stream. Equivale a seek(0, 1).

flush() None

Svuota eventuali buffer di scrittura, inviando i dati in sospeso al dispositivo o file sottostante. Non ha effetto sugli stream privi di buffer.

Iterando direttamente uno stream si ottiene una riga per iterazione, equivalente a chiamare readline() in un ciclo finché non viene restituito il sentinel di fine stream (riga vuota). Uno stream supporta anche il protocollo context manager, quindi with open(...) as f: chiude lo stream automaticamente.

Nota

Il modulo stream di MicroPython espone anche gli helper C con suffisso «1» mp_stream_read1_obj, mp_stream_readinto1_obj e mp_stream_write1_obj che eseguono una singola chiamata di I/O sottostante invece di iterare finché la richiesta non è completamente soddisfatta. Vengono utilizzati internamente da classi come machine.UART per implementare le proprie read / write, ma nessuna classe stream standard li associa come metodi read1 / readinto1 / write1 richiamabili da Python.

class io.StringIO(string: str = '')

Oggetto in memoria simile a file per input/output in modalità testo (analogo a un normale file aperto con il modificatore «t»). Il contenuto iniziale può essere specificato con il parametro string (che deve essere una stringa normale). Le istanze supportano anche il protocollo context manager (utilizzabile in un’istruzione with).

read(size: int = -1) str

Legge e restituisce fino a size caratteri. Se size è omesso o negativo, legge e restituisce tutto il contenuto rimanente.

readline(size: int = -1) str

Legge e restituisce una riga. Se viene fornito size, vengono letti al massimo size caratteri.

readinto(buf: bytearray) int

Legge nel buffer scrivibile pre-allocato buf e restituisce il numero di byte letti.

write(s: str) int

Scrive la stringa s e restituisce il numero di caratteri scritti.

seek(offset: int, whence: int = 0) int

Cambia la posizione dello stream a offset rispetto a whence (0 = inizio, 1 = corrente, 2 = fine) e restituisce la nuova posizione assoluta.

tell() int

Restituisce la posizione corrente dello stream.

flush() None

Svuota i buffer di scrittura. Non ha effetto per uno stream in memoria.

close() None

Chiude lo stream e libera il buffer sottostante. Ulteriori operazioni su uno stream chiuso sollevano ValueError.

getvalue() str

Restituisce il contenuto corrente del buffer sottostante.

class io.StringIO(alloc_size: int)

Crea un oggetto StringIO vuoto pre-allocato per contenere fino a alloc_size byte, in modo che la scrittura fino a tale quantità di byte non rialloca il buffer (evitando una situazione di esaurimento della memoria o la frammentazione della memoria). Questo costruttore è un’estensione di MicroPython consigliata solo per casi speciali e librerie di livello di sistema, non per le applicazioni dell’utente finale.

Differenze rispetto a CPython

Questo costruttore è un’estensione di MicroPython.

read(size: int = -1) str

Legge e restituisce fino a size caratteri. Se size è omesso o negativo, legge e restituisce tutto il contenuto rimanente.

readline(size: int = -1) str

Legge e restituisce una riga. Se viene fornito size, vengono letti al massimo size caratteri.

readinto(buf: bytearray) int

Legge nel buffer scrivibile pre-allocato buf e restituisce il numero di byte letti.

write(s: str) int

Scrive la stringa s e restituisce il numero di caratteri scritti.

seek(offset: int, whence: int = 0) int

Cambia la posizione dello stream a offset rispetto a whence (0 = inizio, 1 = corrente, 2 = fine) e restituisce la nuova posizione assoluta.

tell() int

Restituisce la posizione corrente dello stream.

flush() None

Svuota i buffer di scrittura. Non ha effetto per uno stream in memoria.

close() None

Chiude lo stream e libera il buffer sottostante. Ulteriori operazioni su uno stream chiuso sollevano ValueError.

getvalue() str

Restituisce il contenuto corrente del buffer sottostante.

class io.BytesIO(string: bytes = b'')

Oggetto in memoria simile a file per input/output in modalità binaria (analogo a un normale file aperto con il modificatore «b»). Il contenuto iniziale può essere specificato con il parametro string (che deve essere un oggetto bytes). Le istanze supportano anche il protocollo context manager (utilizzabile in un’istruzione with).

read(size: int = -1) bytes

Legge e restituisce fino a size byte. Se size è omesso o negativo, legge e restituisce tutto il contenuto rimanente.

readline(size: int = -1) bytes

Legge e restituisce una riga. Se viene fornito size, vengono letti al massimo size byte.

readinto(buf: bytearray) int

Legge nel buffer scrivibile pre-allocato buf e restituisce il numero di byte letti.

write(b: bytes) int

Scrive l’oggetto simile a bytes b e restituisce il numero di byte scritti.

seek(offset: int, whence: int = 0) int

Cambia la posizione dello stream a offset rispetto a whence (0 = inizio, 1 = corrente, 2 = fine) e restituisce la nuova posizione assoluta.

tell() int

Restituisce la posizione corrente dello stream.

flush() None

Svuota i buffer di scrittura. Non ha effetto per uno stream in memoria.

close() None

Chiude lo stream e libera il buffer sottostante. Ulteriori operazioni su uno stream chiuso sollevano ValueError.

getvalue() bytes

Restituisce il contenuto corrente del buffer sottostante.

class io.BytesIO(alloc_size: int)

Crea un oggetto BytesIO vuoto pre-allocato per contenere fino a alloc_size byte, in modo che la scrittura fino a tale quantità di byte non rialloca il buffer (evitando una situazione di esaurimento della memoria o la frammentazione della memoria). Questo costruttore è un’estensione di MicroPython consigliata solo per casi speciali e librerie di livello di sistema, non per le applicazioni dell’utente finale.

Differenze rispetto a CPython

Questo costruttore è un’estensione di MicroPython.

read(size: int = -1) bytes

Legge e restituisce fino a size byte. Se size è omesso o negativo, legge e restituisce tutto il contenuto rimanente.

readline(size: int = -1) bytes

Legge e restituisce una riga. Se viene fornito size, vengono letti al massimo size byte.

readinto(buf: bytearray) int

Legge nel buffer scrivibile pre-allocato buf e restituisce il numero di byte letti.

write(b: bytes) int

Scrive l’oggetto simile a bytes b e restituisce il numero di byte scritti.

seek(offset: int, whence: int = 0) int

Cambia la posizione dello stream a offset rispetto a whence (0 = inizio, 1 = corrente, 2 = fine) e restituisce la nuova posizione assoluta.

tell() int

Restituisce la posizione corrente dello stream.

flush() None

Svuota i buffer di scrittura. Non ha effetto per uno stream in memoria.

close() None

Chiude lo stream e libera il buffer sottostante. Ulteriori operazioni su uno stream chiuso sollevano ValueError.

getvalue() bytes

Restituisce il contenuto corrente del buffer sottostante.