4

Im trying to make a Script in NodeJS, which returns the first 2 lines of a text file.

Im currently using this code:

// content of index.js
const fs = require('fs')
const readline = require('readline');
const http = require('http')  
const port = 8080
String.prototype.beginsWith = function (string) {
    return(this.indexOf(string) === 0);
};
const requestHandler = (request, response) => {  

  console.log(request.url)
  if (request.url == "/newlines") {
      filename = "allnames.txt"
      readline.createInterface({
            input: fs.createReadStream(filename),
            output: process.stdout
    })

      response.end('Hello Node.js Server!')
  }
  else {
      response.end('Go away!')
  }

}

const server = http.createServer(requestHandler)

server.listen(port, (err) => {  
  if (err) {
    return console.log('something bad happened', err)
  }

  console.log(`server is listening on ${port}`)
})

So this returns all lines, but I only want to let it return the first 2.

How can I do that?

user8393645
  • 110
  • 1
  • 1
  • 13

2 Answers2

19

Solution : Streaming the read

Most efficient for all scenarios.

var lineReader = require('readline').createInterface({
  input: require('fs').createReadStream(__dirname+'/sample.txt'),
});
var lineCounter = 0; var wantedLines = [];
lineReader.on('line', function (line) {
  lineCounter++;
  wantedLines.push(line);
  if(lineCounter==2){lineReader.close();}
});
lineReader.on('close', function() {
  console.log(wantedLines);
  process.exit(0);
});

Solution : Full-Read, then split

(Not efficient for large files) Simple read & new-line split working example :

const fs = require('fs');
fs.readFile(__dirname+'/sample.txt', "utf8", (err, data) => {
  if(err){console.log(err);}else{
    data = data.split("\n"); // split the document into lines
    data.length = 2;    // set the total number of lines to 2
    console.log(data); //Array containing the 2 lines
  }
});

the sample.txt file :

This is line 1
This is line 2
This is line 3
This is line 4
This is line 5

Running this script will output :

[ 'This is line 1', 'This is line 2' ]

REGARDING QUESTION's EXAMPLE CODE : (SUGGESTION)

If the file to be read is going to be the same on every request. You should load it (store it) into a global variable (if not too big) or a new file (would require to be read again in order to be served) at server startup, for example in your listen callback. You will avoid repeating the same task (reading the file into a string, spliting every line, and keeping the first 2) every time someone performs a request on the given route.

Hope it helped.

EMX
  • 6,066
  • 1
  • 25
  • 32
  • 1
    This might be fine for small files, but it's not a good idea when reading the entirety of *large files* into memory. – mscdex Aug 07 '17 at 23:00
  • Theres another option (for example) use [buffer-reader](https://www.npmjs.com/package/buffer-reader) to only read part of the buffer and then transform it to a string. – EMX Aug 07 '17 at 23:05
  • 1
    Improved answer using stream – EMX Aug 07 '17 at 23:09
  • 1
    @EMX. Hello, I am using reaLine to read all lines into an inMemory buffer. I am trying to close it after line 1 with the same solution , with lineReader.close() but it's not working at all, the lineReader still goes through all the 4millions lines contained into my buffer, even though I am closing the lineReader at line 1. Are you sure this is working ? – Deunz Apr 26 '18 at 07:24
  • 1
    @Deunz, (It surely does work...)[https://nodejs.org/api/readline.html] If it isn't working for you, it would be easier to help you if you posted a new question with some code (& node version)... I can assist you better with more vision of your situation. ;) share the url if you decide to do so – EMX Apr 26 '18 at 21:38
  • 1
    @ EMX thanks for feedback. I didn't manage to get this work. I also found a stackoverflow post with exact same issue : [ https://stackoverflow.com/questions/44153552/readline-doesnt-stop-line-reading-after-rl-close-emit-in-nodejs ] As I state in the answer, I found a workaround working perfectly in the line-reader node module : [ https://github.com/nickewing/line-reader ] Thank anyway for helping ! :) – Deunz Apr 27 '18 at 06:55
11

for those of you who can't make the linereader stop, do this:

lineReader.close()
lineReader.removeAllListeners()
Oz Shabat
  • 1,434
  • 17
  • 16