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?
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.
lineReader. eachLine('path/to/file', function(line) { console. log(line); if (line. includes('STOP') { return false; // stop reading } });
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.
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); })
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With