Contactez-nous

Types de streams : Readable, Writable, Duplex, Transform

Comprenez les roles et fonctionnements des streams Readable, Writable, Duplex et Transform en Node.js pour une manipulation precise et efficace des flux de donnees.

Introduction aux differentes categories de flux

L'abstraction des streams en Node.js est puissante car elle est flexible. Pour s'adapter aux divers besoins de manipulation de données (lecture seule, écriture seule, lecture et écriture, transformation), l'API `stream` définit quatre types fondamentaux de flux. Chacun de ces types possède une interface spécifique, des méthodes et des événements qui correspondent à son rôle. Comprendre ces distinctions est essentiel pour choisir et utiliser correctement les streams dans vos applications.

Ces quatre types ne sont pas complètement isolés ; ils partagent des concepts communs et peuvent souvent être interconnectés, notamment via la méthode `pipe()`. Cependant, leur finalité première diffère. Passons en revue chacun de ces types pour comprendre leurs spécificités et leurs cas d'utilisation typiques.

Readable Streams : les sources de donnees

Les streams Readable (lisibles) représentent une source de données à partir de laquelle on peut lire. Ils agissent comme un robinet d'où les données s'écoulent. Lorsque vous lisez depuis un fichier, recevez une requête HTTP sur un serveur, ou interrogez une base de données, vous interagissez souvent avec un stream Readable.

Leur rôle principal est de pousser des données vers un consommateur. Ils émettent typiquement un événement `data` chaque fois qu'un morceau (chunk) de données est prêt à être lu, et un événement `end` lorsque la source n'a plus de données à fournir. D'autres événements clés incluent `error` en cas de problème et `readable` qui signale que des données sont disponibles pour être lues via la méthode `read()`.

Exemples courants :

  • fs.createReadStream() : Lecture du contenu d'un fichier.
  • http.IncomingMessage : Corps d'une requête HTTP reçue par un serveur.
  • process.stdin : Entrée standard du processus.
  • zlib.createGunzip() : Flux de décompression.

On utilise souvent la méthode `pipe()` pour connecter un Readable stream à un Writable stream, laissant Node.js gérer le flux de données et la contre-pression (backpressure).

Writable Streams : les destinations des donnees

A l'opposé des Readable streams, les streams Writable (inscriptibles) représentent une destination vers laquelle on peut écrire des données. Ils agissent comme un évier où les données sont déversées. Ecrire dans un fichier, envoyer une réponse HTTP depuis un serveur, ou écrire dans la sortie standard sont des opérations impliquant des Writable streams.

Leur fonction est de recevoir des données. On leur envoie des données via la méthode `write(chunk)`. Une fois toutes les données envoyées, on appelle la méthode `end()` pour signaler la fin de l'écriture. Des événements importants sont `finish` (émis lorsque toutes les données ont été flushées vers le système sous-jacent), `error` (en cas d'erreur d'écriture) et `drain` (qui signale que le buffer interne est vide et qu'il est possible d'écrire à nouveau sans risque de saturation, essentiel pour gérer la contre-pression).

Exemples courants :

  • fs.createWriteStream() : Ecriture dans un fichier.
  • http.ServerResponse : Corps d'une réponse HTTP envoyée par un serveur.
  • process.stdout / process.stderr : Sorties standard et d'erreur du processus.
  • zlib.createGzip() : Flux de compression.

Duplex Streams : communication bidirectionnelle independante

Les streams Duplex combinent les caractéristiques des streams Readable et Writable, mais de manière indépendante. Cela signifie qu'un stream Duplex peut être utilisé à la fois pour lire des données et pour en écrire, sans que les opérations de lecture et d'écriture soient directement liées l'une à l'autre. Pensez à une conversation téléphonique : vous pouvez parler (écrire) et écouter (lire) simultanément et indépendamment.

Ils implémentent donc à la fois l'interface Readable et l'interface Writable. Les données écrites via `write()` ne sont pas automatiquement émises par la partie Readable du même stream ; elles sont généralement envoyées vers une autre destination, tandis que les données lues proviennent d'une source distincte.

Exemple principal :

  • net.Socket : Les sockets TCP utilisés pour la communication réseau sont l'exemple le plus classique de streams Duplex. Vous pouvez écrire des données pour les envoyer sur le réseau et lire les données reçues du réseau via le même objet socket.

Transform Streams : transformation de donnees a la volee

Les streams Transform sont un type particulier de stream Duplex où la sortie (la partie Readable) est directement calculée à partir de l'entrée (la partie Writable). Ils agissent comme un maillon dans une chaîne qui reçoit des données, les modifie (les transforme), puis les transmet. Pensez à une machine qui reçoit des matières premières (entrée) et produit des objets finis (sortie).

Comme les Duplex, ils implémentent les deux interfaces. Cependant, lorsque vous écrivez des données dans un stream Transform avec `write()`, une logique interne (`_transform()` lors de l'implémentation) traite ces données et peut ensuite les pousser (`push()`) vers sa propre partie Readable pour être consommées en aval. Ils sont parfaits pour des opérations comme la compression, la décompression, le chiffrement, le déchiffrement, ou toute autre modification de données effectuée en cours de flux.

Exemples courants :

  • zlib.createGzip() / zlib.createGunzip() : Compression / décompression Gzip.
  • crypto.createCipheriv() / crypto.createDecipheriv() : Chiffrement / déchiffrement.
  • Streams personnalisés pour parser du JSON, convertir du CSV, filtrer des logs, etc.

Ces quatre types de streams forment la base de la manipulation de flux en Node.js, offrant une flexibilité remarquable pour construire des pipelines de traitement de données efficaces et économes en ressources.