在NodeJS中读取第N行文件

我试图提取一个文件的一行,因为我知道path名和行号,理想情况下,我想这样做, 而不必读取更多的文件

为了我在这里使用的目的,不pipe这是asynchronous还是同步。

我目前(不好)的实现如下所示:

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'); } 

我试图用createReadStream做一些事情,但数据事件似乎从来没有触发。 任何人都可以提供这个问题的直接解决scheme,或者指向一些NodeJS文件系统交互文档,这是比标准库API文档更多的示例驱动?

具有可读的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); }) 

直接解决:

你应该使用slice方法而不是循环。

 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); }) 

对于(var l行)不是循环数组最有效的方法,你应该这样做:

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

asynchronous方式:

 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); }) 

没有阅读更多的文件比必要的

编辑:模块是保留,我build议使用其他模块逐行阅读,例如,使用变换stream: http : //strongloop.com/strongblog/practical-examples-of-the-new-node-js-stream的API /

用BufferedReader :

 var n = 10; var l = null; //Internally it uses a buffer, default 16KB, but you can reduce it to, for example, 4KB doing: //new BufferedReader ("file", { encoding: "utf8", bufferSize: 4*1024 }) new BufferedReader ("file", { encoding: "utf8" }) .on ("error", function (error){ //error console.log (error); }) .on ("line", function (line){ if (!--n){ l = line; //With interrupt you can stop the reading this.interrupt (); } }) .on ("end", function (){ //your Nth line! console.log (l); }) .read (); 

通过删除“fileData”variables中的以前的数据,可以提高FGRibreau答案的性能。

 function(file, line_no, cb){ var stream = fs.createReadStream(file, { flags: 'r', encoding: 'utf-8', fd: null, mode: '0666', bufferSize: 64 * 1024 }); var fileData = ''; stream.on('data', function(data){ fileData += data; var lines = fileData.split('\n'); if(lines.length >= +line_no){ stream.destroy(); cb(null, lines[+line_no]); } // Add this else condition to remove all unnecesary data from the variable else fileData = Array(lines.length).join('\n'); }); stream.on('error', function(){ cb('Error', null); }); stream.on('end', function(){ cb('File end reached without finding line', null); }); }; 

使用一个70000行文件,显示行50000我得到了这些结果:

真实0m3.504s

用户0m0.000s

sys 0m0.015s

对于同样的例子,我得到了以下几点:

真正的0m0.540s

用户0m0.015s

sys 0m0.031s

这也意味着更低的内存消耗。