Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read Nth line of file in NodeJS

Tags:

node.js

I'm attempting to extract a single line of a file, given that I know the pathname and the line number, ideally I'd like to do this without reading any more of the file than is necessary.

For the purpose I'm using here, it doesn't matter if this is async or sync.

My current (bad) implementation looks like this:

function get_line(filename, line_no, callback) {     line_no = parseInt(line_no);     var data = fs.readFileSync(filename, 'utf8');     var lines = data.split("\n");     for (var l in lines) {         if (l == line_no - 1) {             callback(null, lines[l].trim());             return;         }     }     throw new Error('File end reached without finding line'); } 

I tried to do something with a createReadStream, but the data events never seemed to fire. Can anyone provide a direct solution to this problem, or point me towards some NodeJS filesystem interaction documentation that is a little more example driven than the standard library API docs?

like image 924
Glenjamin Avatar asked Jun 18 '11 08:06

Glenjamin


People also ask

How do you read the nth line of a node js file?

According to the documentation, you can use fs. createReadStream(path[, options]) , where: options can include start and end values to read a range of bytes from the file instead of the entire file.

How do you read a specific line from a text file in node?

lineReader. eachLine('path/to/file', function(line) { console. log(line); if (line. includes('STOP') { return false; // stop reading } });

How do I copy files from one directory to another in node JS?

copyFile() method is used to asynchronously copy a file from the source path to destination path. By default, Node. js will overwrite the file if it already exists at the given destination. The optional mode parameter can be used to modify the behavior of the copy operation.


1 Answers

With readable stream

var fs = require('fs');  function get_line(filename, line_no, callback) {     var stream = fs.createReadStream(filename, {       flags: 'r',       encoding: 'utf-8',       fd: null,       mode: 0666,       bufferSize: 64 * 1024     });      var fileData = '';     stream.on('data', function(data){       fileData += data;        // The next lines should be improved       var lines = fileData.split("\n");        if(lines.length >= +line_no){         stream.destroy();         callback(null, lines[+line_no]);       }     });      stream.on('error', function(){       callback('Error', null);     });      stream.on('end', function(){       callback('File end reached without finding line', null);     });  }  get_line('./file.txt', 1, function(err, line){   console.log('The line: ' + line); }) 

Direct solution:

You should use the slice method instead of a loop.

var fs = require('fs');  function get_line(filename, line_no, callback) {     var data = fs.readFileSync(filename, 'utf8');     var lines = data.split("\n");      if(+line_no > lines.length){       throw new Error('File end reached without finding line');     }      callback(null, lines[+line_no]); }  get_line('./file.txt', 9, function(err, line){   console.log('The line: ' + line); }) 

for (var l in lines) isn't the most efficient way for looping over an array, you should do this instead:

for(var i = 0, iMax = lines.length; i < iMax; i++){/* lines[i] */ } 

The asynchronous way:

var fs = require('fs');  function get_line(filename, line_no, callback) {     fs.readFile(filename, function (err, data) {       if (err) throw err;        // Data is a buffer that we need to convert to a string       // Improvement: loop over the buffer and stop when the line is reached       var lines = data.toString('utf-8').split("\n");        if(+line_no > lines.length){         return callback('File end reached without finding line', null);       }        callback(null, lines[+line_no]);     }); }  get_line('./file.txt', 9, function(err, line){   console.log('The line: ' + line); }) 

like image 171
FGRibreau Avatar answered Sep 23 '22 02:09

FGRibreau