io — flux d’entrée/sortie

Ce module contient des types supplémentaires d’objets stream (de type fichier) ainsi que des fonctions utilitaires. Il expose la fonction native open() ainsi que des tampons texte et binaires en mémoire (StringIO, BytesIO) qui implémentent l’interface de flux standard read/write/seek.

Hiérarchie conceptuelle

Différence avec CPython

La hiérarchie conceptuelle des classes de base de flux est simplifiée dans MicroPython, comme décrit dans cette section.

Les classes de flux de base (abstraites), qui servent de fondation au comportement de toutes les classes concrètes, respectent quelques dichotomies (classifications par paires) dans CPython. Dans MicroPython, elles sont quelque peu simplifiées et rendues implicites afin d’atteindre une meilleure efficacité et d’économiser les ressources.

Une dichotomie importante dans CPython est celle des flux avec tampon (buffered) ou sans tampon (unbuffered). Dans MicroPython, tous les flux sont actuellement sans tampon. C’est parce que tous les systèmes d’exploitation modernes, et même de nombreux RTOS et pilotes de système de fichiers, effectuent déjà une mise en tampon de leur côté. Ajouter une autre couche de mise en tampon est contre-productif (un problème connu sous le nom de « bufferbloat ») et consomme de la mémoire précieuse. Notez qu’il existe encore des cas où la mise en tampon peut être utile, donc nous pourrions introduire une prise en charge optionnelle de la mise en tampon ultérieurement.

Mais dans CPython, une autre dichotomie importante est liée à la « mise en tampon » : c’est de savoir si un flux peut subir des lectures/écritures partielles ou non. Une lecture partielle se produit lorsqu’un utilisateur demande par exemple 10 octets à un flux, mais en obtient moins ; de même pour les écritures. Dans CPython, les flux sans tampon sont automatiquement susceptibles d’opérations partielles, tandis que les flux avec tampon en sont garantis exempts. L’absence de lectures/écritures partielles est un trait important, car elle permet de développer des programmes plus concis et efficaces - chose hautement souhaitable pour MicroPython. Ainsi, bien que MicroPython ne prenne pas en charge les flux avec tampon, il fournit néanmoins des flux sans opérations partielles. La présence ou non d’opérations partielles dépend des besoins de chaque classe particulière, mais il est fortement conseillé aux développeurs de privilégier le comportement sans opérations partielles pour les raisons exposées ci-dessus. Par exemple, les sockets MicroPython sont garantis d’éviter les lectures/écritures partielles. En réalité, à l’heure actuelle, il n’existe aucun exemple de classe de flux à opérations partielles dans le cœur, et une telle classe serait spécifique à un matériel particulier.

Le comportement sans opérations partielles devient délicat dans le cas des flux non bloquants, le comportement bloquant ou non bloquant étant une autre dichotomie de CPython, entièrement prise en charge par MicroPython. Les flux non bloquants n’attendent jamais que des données arrivent ou soient écrites - ils lisent/écrivent ce qui est possible, ou signalent l’absence de données (ou la capacité d’écrire des données). De toute évidence, cela entre en conflit avec la politique « sans opérations partielles », et en effet, le cas des flux non bloquants avec tampon (et donc sans opérations partielles) est alambiqué dans CPython - à certains endroits, une telle combinaison est interdite, à d’autres elle est indéfinie ou simplement non documentée, et dans certains cas elle lève des exceptions verbeuses. La question est beaucoup plus simple dans MicroPython : les flux non bloquants sont importants pour des opérations asynchrones efficaces, donc cette propriété prévaut sur celle de l”« absence d’opérations partielles ». Ainsi, alors que les flux bloquants éviteront les lectures/écritures partielles dans la mesure du possible (le seul cas où l’on obtient une lecture partielle est lorsque la fin du fichier est atteinte, ou en cas d’erreur (mais les erreurs ne renvoient pas de données partielles, elles lèvent des exceptions)), les flux non bloquants peuvent produire des données partielles afin d’éviter de bloquer l’opération.

La dernière dichotomie est celle des flux binaires ou texte. MicroPython prend bien sûr en charge ces deux types, mais alors que dans CPython les flux texte sont intrinsèquement mis en tampon, ils ne le sont pas dans MicroPython. (En effet, c’est l’un des cas pour lesquels nous pourrions introduire la prise en charge de la mise en tampon.)

Notez que pour des raisons d’efficacité, MicroPython ne fournit pas de classes de base abstraites correspondant à la hiérarchie ci-dessus, et il n’est pas possible d’implémenter, ou de dériver, une classe de flux en pur Python.

Fonctions

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

Ouvre un fichier. La fonction native open() est un alias de cette fonction. Le paramètre mode est toujours pris en charge ; la prise en charge des autres arguments peut varier.

Classes

class io.IOBase

Classe de base pour les objets de flux (de type « fichier »). Les sous-classes concrètes implémentent les méthodes d’E/S de bas niveau ci-dessous (readinto, write, ioctl) ; le runtime construit le protocole de flux de plus haut niveau (read, readline, readlines, close, itération) par-dessus, de sorte que chaque instance de flux prend en charge ces méthodes même lorsque la sous-classe ne les définit pas.

Méthodes d’implémentation (à redéfinir dans une sous-classe) :

readinto(buf: bytearray) int | None

Lit des octets dans le tampon accessible en écriture buf. Renvoie le nombre d’octets lus, 0 en fin de flux, ou None si aucune donnée n’est disponible pour le moment (pour un flux non bloquant).

write(buf: bytes) int | None

Écrit les octets contenus dans buf. Renvoie le nombre d’octets écrits, ou None si l’écriture ne peut pas être effectuée pour le moment (pour un flux non bloquant).

ioctl(request: int, arg: int) int

Contrôle le flux/périphérique sous-jacent. request est l’un des codes de requête MP_STREAM_*. Renvoie une valeur non négative en cas de succès, ou une valeur errno négative en cas d’erreur.

Méthodes du protocole de flux (disponibles sur chaque instance de flux) :

read(size: int = -1)

Lit et renvoie jusqu’à size octets (ou caractères, en mode texte). Si size est omis ou négatif, lit jusqu’à la fin du flux. Renvoie bytes pour les flux binaires et str pour les flux texte ; un résultat vide indique la fin du flux.

readline(size: int = -1)

Lit et renvoie une ligne, y compris le caractère de fin de ligne s’il est présent. Si size est fourni, au plus size octets (ou caractères) sont lus. Renvoie une chaîne bytes / str vide en fin de flux.

readlines() list

Lit jusqu’à la fin du flux et renvoie une list de lignes, chacune avec son caractère de fin de ligne.

close() None

Ferme le flux et libère toutes les ressources sous-jacentes. Les opérations sur un flux fermé lèvent OSError (ou ValueError pour les flux en mémoire).

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

Change la position courante du flux à offset octets relativement à whence (0 = début du flux, 1 = position courante, 2 = fin du flux). Renvoie la nouvelle position absolue. Lève OSError sur un flux qui n’est pas positionnable.

tell() int

Renvoie la position absolue courante dans le flux. Équivalent à seek(0, 1).

flush() None

Vide tous les tampons d’écriture, en poussant les données en attente vers le périphérique ou le fichier sous-jacent. Sans effet sur les flux qui n’utilisent pas de tampon.

Itérer directement sur un flux produit une ligne par itération – équivalent à appeler readline() dans une boucle jusqu’à ce que la sentinelle de fin de flux (ligne vide) soit renvoyée. Un flux prend également en charge le protocole de gestionnaire de contexte, de sorte que with open(...) as f: ferme le flux automatiquement.

Note

Le module de flux de MicroPython expose également des fonctions utilitaires C suffixées par « 1 » : mp_stream_read1_obj, mp_stream_readinto1_obj et mp_stream_write1_obj, qui effectuent un seul appel d’E/S sous-jacent au lieu de boucler jusqu’à ce que la requête soit entièrement satisfaite. Elles sont utilisées en interne par des classes comme machine.UART pour implémenter leurs propres read / write – mais aucune classe de flux standard ne les lie en tant que méthodes read1 / readinto1 / write1 appelables depuis Python.

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

Objet en mémoire de type fichier pour les entrées/sorties en mode texte (similaire à un fichier normal ouvert avec le modificateur « t »). Le contenu initial peut être spécifié avec le paramètre string (qui doit être une chaîne normale). Les instances prennent également en charge le protocole de gestionnaire de contexte (utilisable dans une instruction with).

read(size: int = -1) str

Lit et renvoie jusqu’à size caractères. Si size est omis ou négatif, lit et renvoie tout le contenu restant.

readline(size: int = -1) str

Lit et renvoie une ligne. Si size est fourni, au plus size caractères sont lus.

readinto(buf: bytearray) int

Lit dans le tampon préalloué et accessible en écriture buf et renvoie le nombre d’octets lus.

write(s: str) int

Écrit la chaîne s et renvoie le nombre de caractères écrits.

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

Change la position du flux à offset relativement à whence (0 = début, 1 = position courante, 2 = fin) et renvoie la nouvelle position absolue.

tell() int

Renvoie la position courante du flux.

flush() None

Vide les tampons d’écriture. Cela est sans effet pour un flux en mémoire.

close() None

Ferme le flux et libère le tampon sous-jacent. Toute opération ultérieure sur un flux fermé lève ValueError.

getvalue() str

Renvoie le contenu courant du tampon sous-jacent.

class io.StringIO(alloc_size: int)

Crée un objet StringIO vide préalloué pour contenir jusqu’à alloc_size octets, de sorte que l’écriture de ce nombre d’octets ne réallouera pas le tampon (évitant une situation de manque de mémoire ou la fragmentation de la mémoire). Ce constructeur est une extension de MicroPython recommandée uniquement pour des cas particuliers et les bibliothèques de niveau système, pas pour les applications utilisateur final.

Différence avec CPython

Ce constructeur est une extension de MicroPython.

read(size: int = -1) str

Lit et renvoie jusqu’à size caractères. Si size est omis ou négatif, lit et renvoie tout le contenu restant.

readline(size: int = -1) str

Lit et renvoie une ligne. Si size est fourni, au plus size caractères sont lus.

readinto(buf: bytearray) int

Lit dans le tampon préalloué et accessible en écriture buf et renvoie le nombre d’octets lus.

write(s: str) int

Écrit la chaîne s et renvoie le nombre de caractères écrits.

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

Change la position du flux à offset relativement à whence (0 = début, 1 = position courante, 2 = fin) et renvoie la nouvelle position absolue.

tell() int

Renvoie la position courante du flux.

flush() None

Vide les tampons d’écriture. Cela est sans effet pour un flux en mémoire.

close() None

Ferme le flux et libère le tampon sous-jacent. Toute opération ultérieure sur un flux fermé lève ValueError.

getvalue() str

Renvoie le contenu courant du tampon sous-jacent.

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

Objet en mémoire de type fichier pour les entrées/sorties en mode binaire (similaire à un fichier normal ouvert avec le modificateur « b »). Le contenu initial peut être spécifié avec le paramètre string (qui doit être un objet bytes). Les instances prennent également en charge le protocole de gestionnaire de contexte (utilisable dans une instruction with).

read(size: int = -1) bytes

Lit et renvoie jusqu’à size octets. Si size est omis ou négatif, lit et renvoie tout le contenu restant.

readline(size: int = -1) bytes

Lit et renvoie une ligne. Si size est fourni, au plus size octets sont lus.

readinto(buf: bytearray) int

Lit dans le tampon préalloué et accessible en écriture buf et renvoie le nombre d’octets lus.

write(b: bytes) int

Écrit l’objet de type bytes b et renvoie le nombre d’octets écrits.

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

Change la position du flux à offset relativement à whence (0 = début, 1 = position courante, 2 = fin) et renvoie la nouvelle position absolue.

tell() int

Renvoie la position courante du flux.

flush() None

Vide les tampons d’écriture. Cela est sans effet pour un flux en mémoire.

close() None

Ferme le flux et libère le tampon sous-jacent. Toute opération ultérieure sur un flux fermé lève ValueError.

getvalue() bytes

Renvoie le contenu courant du tampon sous-jacent.

class io.BytesIO(alloc_size: int)

Crée un objet BytesIO vide préalloué pour contenir jusqu’à alloc_size octets, de sorte que l’écriture de ce nombre d’octets ne réallouera pas le tampon (évitant une situation de manque de mémoire ou la fragmentation de la mémoire). Ce constructeur est une extension de MicroPython recommandée uniquement pour des cas particuliers et les bibliothèques de niveau système, pas pour les applications utilisateur final.

Différence avec CPython

Ce constructeur est une extension de MicroPython.

read(size: int = -1) bytes

Lit et renvoie jusqu’à size octets. Si size est omis ou négatif, lit et renvoie tout le contenu restant.

readline(size: int = -1) bytes

Lit et renvoie une ligne. Si size est fourni, au plus size octets sont lus.

readinto(buf: bytearray) int

Lit dans le tampon préalloué et accessible en écriture buf et renvoie le nombre d’octets lus.

write(b: bytes) int

Écrit l’objet de type bytes b et renvoie le nombre d’octets écrits.

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

Change la position du flux à offset relativement à whence (0 = début, 1 = position courante, 2 = fin) et renvoie la nouvelle position absolue.

tell() int

Renvoie la position courante du flux.

flush() None

Vide les tampons d’écriture. Cela est sans effet pour un flux en mémoire.

close() None

Ferme le flux et libère le tampon sous-jacent. Toute opération ultérieure sur un flux fermé lève ValueError.

getvalue() bytes

Renvoie le contenu courant du tampon sous-jacent.