1
votes

Comment utiliser readline dans NodeJs sur un événement (attendre la fermeture du flux)

Je crée un bot qui, lorsqu'il reçoit un message, commence à lire un fichier texte et répond au message avec le contenu du fichier.

Malheureusement, je ne peux pas sortir de cet enfer asynchrone et je n'obtient que des erreurs, indéfinies ou promises

La dernière expérience était la suivante:

const fs = require('fs');
const readline = require('readline');

// bot.listen("message").reply(responseText())

function readFile(file) {
    var text = '';
        var readInterface = readline.createInterface({
            input: fs.createReadStream(file),
            terminal: false
        });

        readInterface.on('line', function(line) {
            linea = line.trim();
            console.log(linea);
            text += linea;
        }).on('close', function() {
            return text;
        });
    });
}

async function responseText() {
    var content = await readFile("file.txt");
    content.then(function(data) {
        return data;
    })
}

Ce que je voudrais alors, c'est retarder la réponse jusqu'à ce que j'obtienne le contenu du fichier. Je sais que ce nœud est basé sur async mais je ne sais pas comment le gérer!

Merci à tous


1 commentaires

Si vous souhaitez lire un fichier, vous n'avez pas besoin d'utiliser readline et de concaténer le fichier, ligne par ligne, en une chaîne. Utilisez simplement fs.readFile () , comme dans fs.readFile ("file.txt", "utf8", (err, contents) => {console.log (contents);});


3 Réponses :


2
votes

Si vous souhaitez utiliser async-await , vous devez créer une promesse et la renvoyer.

function readFile(file) {
    return new Promise((res, rej) => {
        try {
            var text = '';
            var readInterface = readline.createInterface({
                input: fs.createReadStream(file),
                terminal: false
            });

            readInterface
                .on('line', function (line) {
                    linea = line.trim();
                    text += linea;
                })
                .on('close', function () {
                    res(text);
                });
        } catch(err){
            rej(err)
        }
    });
}


0 commentaires

0
votes

Si vous utilisez express.js ou tout autre framework construit dessus, vous pouvez simplement diriger le flux de lecture vers la réponse puisque les réponses express sont des flux pour commencer par:

const es = require('event-stream')
...
let getFileStream = path => (
fs.createReadStream(path)
.pipe(es.split())
.pipe(es.map(function (data, cb) { 
      cb(null
        , inspect(JSON.parse(data)))  
    }))
);

router.get('/message', function (req, res, next) {
   let file$ = getFileStream(yourFilePath)
       file$.on('error', next).pipe(res)

})

Si vous avez besoin pour transformer le contenu du fichier, vous pouvez utiliser un flux de transformation ou comme indiqué dans l'exemple ci-dessus, un mappage de flux d'événements synchrone. L'idée est de toujours jouer avec le contenu du fichier au niveau du flux pour éviter d'avoir à charger tout le contenu du fichier en mémoire.

Vous ne voulez pas vraiment mettre en mémoire tampon tout le contenu du fichier en mémoire. Cela peut rapidement devenir un problème avec des fichiers volumineux lors d'une journée chargée. ce dont vous avez besoin est de diriger le flux de fichiers directement vers le navigateur. Le même principe s'applique à tout type de consommateur.

Bien sûr, si le mécanisme est entièrement interne, vous ne devez transmettre le chemin du fichier ou le flux réel que jusqu'à ce que vous ayez réellement besoin d'ouvrir le fichier et de faire quelque chose avec le contenu. Dans ce cas, vous revenez à votre boîte à outils de flux, qu'il s'agisse de l'implémentation native de l'API de flux node.js, du package de flux d'événements ou d'une sorte de bibliothèque observable comme rxjs.


0 commentaires

0
votes

J'ai eu un problème similaire dans une application qui surveille un répertoire pour les nouveaux fichiers, lit le (s) fichier (s) et renvoie les données dérivées en fonction du contenu du fichier. La fonction My Reader est basée sur cet exemple async de la documentation nodejs. Je renvoie les options , qui contiennent le contexte, uniquement après la lecture complète du fichier.

/**
 * @desc callback to instruct what to do with each line read
 *
 * @param {*} line
 */
const readFileLine = function (line) {
  linea = line.trim();
  console.log(linea);
  text += linea;
  this.context += linea
}

/**
 * @desc once the added file is ready to be processed read file line by line
 * @listens {Event} listens for `process` event
*/
const readFile = (options) => {
  return Reader(options)
}

/**
 * @desc Call the file reader and do what you need with the reponse
 * 
*/
const getResponseFromFiles = (file) => {
  const opts = {}
  opts.cb = readFileLine.bind(opts)
  opts.context = ''
  opts.file = file
  readFile(opts)
  .then(data => {
      process.exitCode = 0
      console.log(data)
      return data
    })
    .catch(err => {
      process.exitCode = 1
      console.log(err.message)
    })
}

J'ai alors un fichier qui importe mon Reader et définit comment l'utiliser. Je définis une fonction de rappel à passer à l'écouteur d'événement line . Je lie le rappel à l'objet d'options que je passe à ma fonction Reader. dans le Fonction readFile Je m'assure de renvoyer l'appel à Reader, qui est une promesse.

const { createReadStream } = require('fs')
const { createInterface } = require('readline')
const { once } = require('events')

// Reader.js
async function Reader (options) {
  let { file, cb } = options
  let fileStream = createReadStream(file)

  const readInterface = createInterface({
    input: fileStream,
    crlfDelay: Infinity
  })

  readInterface.on('line', (line) => {
    cb(line)
  })

  await once(readInterface, 'close')
  return options
}
module.exports = Reader


0 commentaires