Les Streams

Voir la vidéo
Description Sommaire

Dans le chapitre précédent nous avons vu comment lire un fichier à l'aide de la méthode fs.readFile(). Cette méthode convient très bien pour la lecture de fichiers de petite taille mais peut s'avérer problématique pour de gros fichiers car elle oblige NodeJS à stocker le résultat de la lecture dans une variable. Si on essaie alors de lire des fichiers plus volumineux on peut alors très rapidement rencontré des problèmes.

Les streams

Un stream, permet de lire et d'écrire un contenu sous forme de flux et de recevoir les informations sous forme de petits blocs plus digestes pour la mémoire. Ces streams peuvent être de plusieurs nature :

  • Readable, pour un flux qui ne fait que lire des informations (comme par exemple fs.createReadStream())
  • Writable, pour un flux qui écrit les données qu'il reçoit (fs.createWriteStream())
  • Duplex, pour un flux qui est à la fois capable de lire et d'écrire
  • Transform, pour un flux qui peut lire et transformer les information lors de la lecture ou de l'écriture (par exemple zlib.createDeflate())

Comme pour le reste des objets de NodeJS ces flux utilisent le modèle d'évènement pour émettre des évènement lorsque certaines actions sont atteintes. Par exemple, un readable stream possèdera un évènement data qui permettra de suivre l'état de lecture du fichier.

let fs = require('fs')
let file = 'demo.mp4'

fs.stat(file, (err, stat) => {
  let total = stat.size
  let progress = 0
  let read = fs.createReadStream(file)
  read.on('data', (chunk) => {
    progress += chunk.length
    console.log("J'ai lu " + Math.round(100 * progress / total) + "%")
  })
})

Les flux d'écriture possèdent quand à eux une méthode write() qui permet d'écrire les données. Cette méthode peut renvoyer false pour indiquer que l'écriture n'est pas disponible et que le flux doit être mis en pause jusqu'à que l'évènement drain soit renvoyé.

function writeOneMillionTimes(writer, data, encoding, callback) {
  let i = 1000000
  write()
  function write() {
    var ok = true // Permet de savoir si le flux peut accepter de nouvelles écritures
    while (i > 0 && ok) {
      i--
      if (i === 0) {
        // on écrit le denier morceau, on passe donc le callback en 3ème paramètre
        writer.write(data, encoding, callback)
      } else {
        // on écrit dans le stream et on stocke le succès ou l'échec de l'écriture
        ok = writer.write(data, encoding)
      }
    } 
    if (i > 0) {
      // On ne déclenche une nouvelle écriture que lorsque le flux est prêt
      writer.once('drain', write)
    }
  }
}

Rassurez vous, NodeJS intègre une méthode permettant de relier des flux entre eux afin d'éviter d'avoir à tout cabler manuellement. Que se passe-t-il si on veut copier un fichier par exemple ? Les flux de lecture possèdent une méthode pipe() qui permet d'attacher un flux d'écriture. Le flux de données sera automatiquement géré afin que le flux d'écriture ne soit pas submerger par une lecture trop rapide des informations.

let fs = require('fs')
let file = 'demo.mp4'

fs.stat(file, (err, stat) => {
  let total = stat.size
  let progress = 0
  let read = fs.createReadStream(file)
  let write = fs.createWriteStream('copy.mp4')
  read.on('data', (chunk) => {
    progress += chunk.length
    console.log("J'ai lu " + Math.round(100 * progress / total) + "%")
  })
  // Un simple pipe suffit pour brancher notre lecture à notre écriture, NodeJS se charge du reste :)
  read.pipe(write)
  write.on('finish', () => {
    console.log('Le fichier a bien été copié')
  })
})
Publié
Technologies utilisées
Auteur :
Grafikart
Partager