0

I have following code:

const fs = require("fs");
const {createInterface} = require("readline");
const {join} = require("path");
const {once} = require("events");

async function readMeta (path) {
    const meta = {};
    const rs = fs.createReadStream(path);
    const lineReader = createInterface({input: rs});

    let linesRead = 0;

    lineReader.on("line", line => {

        switch (linesRead) {
            case 0:
                meta.name = line;
                break;
            case 1:
                meta.tags = line.split(" ");
                break;
            case 2:
                meta.type = line;
                break;
            case 3:
                meta.id = +line;
        }

        if (++linesRead === 4) {
            lineReader.close();
        }
    });
    await once(lineReader, "close");
    rs.close();
    return meta;
}

It appears to be working, but logging the lines when the line event fires reveals otherwise. The event is still being fired after lineReader.close() has been called resulting in the whole file being read. I have no idea what is causing this. I found some modules that apparently does the job, but i want do keep the dependencies down if possible.

  • better `await once(lineReader, 'end');` https://github.com/maleck13/readline/blob/master/readline.js#L51 file may not be closed or closed quickly, but Your goal is to catch when it ends reading. – num8er Mar 01 '20 at 14:31
  • im not sure i understand what you mean, my goal is to make it stop reading, i don't want to read the entire file. – dude123123123 Mar 01 '20 at 14:55
  • how about calling `rs.close();` right after `lineReader.close();`cause line reader takes input from read stream which is does not close – num8er Mar 01 '20 at 14:57
  • `rs` is being closed when `lineReader` fires it's `close` event. – dude123123123 Mar 01 '20 at 15:20
  • 1
    please read" https://nodejs.org/api/readline.html#readline_rl_close `Calling rl.close() does not immediately stop other events (including 'line') from being emitted by the readline.Interface instance.` which means that You've to close read stream first – num8er Mar 01 '20 at 15:24
  • I already tried but it doesn't make a difference – dude123123123 Mar 01 '20 at 15:37

1 Answers1

0

Instead of handling and switching counter I recommend to push lines to array and prevent further push-ing after array size is 4.

Then to call close and after to destructure array to necessary attributes and return object that contains them.

const fs = require("fs");
const {createInterface} = require("readline");
const {join} = require("path");
const {once} = require("events");

async function readMeta (path) {
    const meta = {};
    const rs = fs.createReadStream(path);
    const lineReader = createInterface({input: rs});

    const linesRead = [];

    lineReader.on("line", line => {
      if (linesRead.length === 4) {
        lineReader.close();
        rs.close();
        return;
      }
      linesRead.push(line.trim());
    });

    await once(lineReader, "close");
    delete rs;
    delete lineReader;

    const [name, tags, type, id] = linesRead;
    return {
      id,
      name,
      type,
      tags: tags.split(' '),
    };
}
num8er
  • 18,604
  • 3
  • 43
  • 57