Le module `io` en Python
Cet article explique le module io en Python.
Nous allons expliquer le module io en Python à l'aide d'exemples concrets.
YouTube Video
Le module io en Python
Le traitement des entrées/sorties constitue la base de toutes sortes d'opérations sur les données, telles que les fichiers, les réseaux et l'E/S standard. Le module io de Python fournit un ensemble de classes abstraites qui unifient ces opérations d'entrée/sortie. Le concept clé pour comprendre ce module est celui de "flux" (stream).
Qu'est-ce qu'un flux ?
Un flux est un flux abstrait pour lire et écrire des données de manière séquentielle et continue.
Lorsque l'on lit le contenu d'un fichier octet par octet ou que l'on envoie et reçoit des données sur un réseau, tout cela peut être traité comme des flux de données.
En généralisant ce mécanisme, les fichiers, la mémoire et les réseaux, c’est-à-dire des sources d’E/S différentes, peuvent être traités avec des opérations communes telles que la lecture et l’écriture.
Le module io de Python fournit une interface unifiée pour les flux, permettant une gestion efficace des données textuelles et binaires.
Structure de base du module io
Le module io dispose d'une hiérarchie en trois couches en fonction de la nature des flux.
-
Couche brute (
RawIOBase)RawIOBasegère les E/S octet par octet au niveau le plus bas, comme les descripteurs de fichiers du système d’exploitation et les périphériques. -
Couche tamponnée (
BufferedIOBase)BufferedIOBasefournit un cache (tampon) pour améliorer l’efficacité des E/S.BufferedReaderetBufferedWriteren sont des exemples typiques. -
Couche texte (
TextIOBase)TextIOBaseconvertit des séquences d’octets en chaînes de caractères et gère le codage. Généralement, lorsqu’on ouvre un fichier avec la fonctionopen(), c’estTextIOWrapperde cette couche qui est utilisé.
Grâce à cette structure, le module io sépare clairement les E/S texte et binaire tout en permettant des combinaisons flexibles.
Structure de base du module io
RawIOBase gère les descripteurs de fichiers du système d’exploitation à la couche la plus basse, BufferedIOBase ajoute un cache au-dessus, et la couche supérieure TextIOBase s’occupe de la conversion des chaînes.
1import io
2
3# Check the core base classes hierarchy
4print(io.IOBase.__subclasses__())- Ce code permet de vérifier le groupe de classes abstraites qui héritent de
IOBase. On peut voirTextIOBase,BufferedIOBaseetRawIOBase, ce qui confirme la structure hiérarchique.
io.IOBase : La classe de base de toutes
IOBase est la classe de base abstraite pour tous les objets d’E/S, définissant les méthodes communes comme close(), flush() et seekable(). Elle est rarement utilisée directement et on y accède généralement via des classes dérivées.
1import io
2
3f = io.StringIO("data")
4print(f.seekable()) # True
5print(f.readable()) # True
6print(f.writable()) # True
7f.close()- Cet exemple montre que les méthodes communes de
IOBasepeuvent également être utilisées dans les classes supérieures.seekable()etreadable()sont utiles pour vérifier les propriétés d’un flux.
io.RawIOBase : La couche la plus basse
RawIOBase est la couche la plus proche du descripteur de fichier de l’OS et n’effectue pas de mise en tampon. L’implémentation typique est FileIO, qui effectue la lecture et l’écriture octet par octet.
1import io, os
2
3# Create a low-level FileIO object (no buffering)
4fd = os.open('raw_demo.bin', os.O_RDWR | os.O_CREAT)
5raw = io.FileIO(fd, mode='w+')
6raw.write(b'abc123')
7raw.seek(0)
8print(raw.read(6)) # b'abc123'
9raw.close()FileIOest une implémentation concrète deRawIOBase; toutes les lectures et écritures sont effectuées en tant quebytes. L’efficacité peut être améliorée en le combinant avec la couche supérieureBufferedIOBase.
io.BufferedIOBase : Couche intermédiaire (avec tampon)
BufferedIOBase est une couche intermédiaire qui fait du tamponnement, rendant l’accès au disque plus efficace. Les principales implémentations sont BufferedReader, BufferedWriter, BufferedRandom et BufferedRWPair.
1import io
2
3# Create a buffered binary stream on top of a BytesIO (simulate file)
4base = io.BytesIO()
5buffered = io.BufferedWriter(base)
6buffered.write(b'Python IO buffering')
7buffered.flush()
8base.seek(0)
9print(base.read()) # b'Python IO buffering'- Dans cet exemple, les données écrites via
BufferedWritersont temporairement stockées dans un tampon en mémoire et sont effectivement transférées à la couche inférieure lors de l’appel àflush().
Exemple de BufferedReader
BufferedReader est un flux tamponné en lecture seule qui prend en charge une lecture efficace avec peek() et read().
1import io
2
3stream = io.BytesIO(b"1234567890")
4reader = io.BufferedReader(stream)
5print(reader.peek(5)) # b'12345' (non-destructive)
6print(reader.read(4)) # b'1234'
7print(reader.read(3)) # b'567'peek()ne fait qu'observer (peek) les données et ne déplace pas le pointeur. En le combinant avecread(), on peut contrôler de manière flexible la mise en tampon.
io.TextIOBase : Couche texte seulement
TextIOBase est une couche d'abstraction pour la gestion des chaînes de caractères, effectuant en interne le décodage et l'encodage. Une classe d’implémentation typique est TextIOWrapper.
1import io
2
3# Wrap a binary stream to handle text encoding
4binary = io.BytesIO()
5text_stream = io.TextIOWrapper(binary, encoding='utf-8')
6text_stream.write("\u3053\u3093\u306B\u3061\u306F")
7text_stream.flush()
8
9# Reset stream position
10binary.seek(0)
11
12# Read bytes once
13data = binary.read()
14
15# Show both raw bytes and decoded text
16print("Raw bytes:", data)
17print("Decoded text:", data.decode('utf-8'))- Dans cet exemple,
TextIOWrapperencode la chaîne en UTF-8 et l’écrit dans le flux binaire sous-jacent.
Exemple de lecture avec TextIOWrapper
Le décodage est effectué automatiquement lors de la lecture.
1import io
2
3binary_data = io.BytesIO("Python I/O".encode('utf-8'))
4text_reader = io.TextIOWrapper(binary_data, encoding='utf-8')
5print(text_reader.read()) # 'Python I/O'TextIOWrappersert de classe fondamentale pour l’E/S texte et constitue la base de presque toutes les opérations de fichiers de haut niveau.
io.StringIO : Flux texte en mémoire
StringIO est une classe qui permet de traiter des chaînes de caractères en mémoire comme s’il s’agissait de fichiers. Elle est utile pour les tests d’E/S et la génération temporaire de données.
1import io
2
3text_buf = io.StringIO()
4text_buf.write("In-memory text stream")
5text_buf.seek(0)
6print(text_buf.read()) # 'In-memory text stream'StringIOpermet d’effectuer des opérations similaires à des fichiers sans utiliser le disque et est largement utilisé pour les tests unitaires.
io.BytesIO : Flux binaire en mémoire
BytesIO est une classe de fichier en mémoire pour manipuler des séquences d’octets (bytes). Elle est utile pour des situations telles que le traitement binaire ou la compression de données où l’on ne souhaite pas utiliser de fichiers.
1import io
2
3buf = io.BytesIO()
4buf.write(b'\x01\x02\x03')
5buf.seek(0)
6print(list(buf.read())) # [1, 2, 3]BytesIOpossède la même interface queBufferedIOBaseet peut être utilisé comme substitut à de nombreuses API de fichiers.
Flux personnalisés (création de classes originales)
Les classes du module io sont extensibles, ce qui permet de créer vos propres classes de flux. Voici ci-dessous un exemple de sous-classe TextIOBase qui met tout le texte en majuscules lors de l’écriture.
1import io
2
3class UpperTextIO(io.TextIOBase):
4 def __init__(self):
5 self.buffer = ""
6 def write(self, s):
7 self.buffer += s.upper()
8 return len(s)
9
10u = UpperTextIO()
11u.write("hello io")
12print(u.buffer) # "HELLO IO"- Tant que vous respectez le contrat de
TextIOBase, vous pouvez définir n’importe quel comportement personnalisé comme celui-ci. Il est également facile d’étendre les flux pour des usages spécifiques, comme les fichiers et les réseaux.
Résumé
Le module io organise le traitement des entrées/sorties dans une hiérarchie de classes abstraites et concrètes.
RawIOBaseest une classe pour les E/S octet par octet au niveau du système d’exploitation.BufferedIOBaseest une classe qui fournit une couche de cache efficace.TextIOBaseest une classe qui gère la lecture et l’écriture de chaînes de caractères.StringIOetBytesIOsont des classes qui fournissent des flux en mémoire.
Comprendre ces classes vous permet de saisir précisément le fonctionnement du système d’E/S de Python et de les appliquer aux opérations sur les fichiers, à la communication réseau et à la conception de flux de test.
Vous pouvez suivre l'article ci-dessus avec Visual Studio Code sur notre chaîne YouTube. Veuillez également consulter la chaîne YouTube.