Node.js: Count the number of lines in a file
我有大文本文件,范围在
我有这些限制:
- 整个文件不需要写入内存
- 执行任务不需要子进程
不使用wc的解决方案:
1 2 3 4 5 6 7 8 9 10 | var i; var count = 0; require('fs').createReadStream(process.argv[2]) .on('data', function(chunk) { for (i=0; i < chunk.length; ++i) if (chunk[i] == 10) count++; }) .on('end', function() { console.log(count); }); |
它的速度较慢,但??不是那么多 - 140M +文件的0.6s包括node.js loading&amp;启动时间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | >time node countlines.js video.mp4 619643 real 0m0.614s user 0m0.489s sys 0m0.132s >time wc -l video.mp4 619643 video.mp4 real 0m0.133s user 0m0.108s sys 0m0.024s >wc -c video.mp4 144681406 video.mp4 |
你可以这样做,因为评论建议使用
1 2 3 4 5 | var exec = require('child_process').exec; exec('wc /path/to/file', function (error, results) { console.log(results); }); |
我们可以使用indexOf让VM找到换行符:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | function countFileLines(filePath){ return new Promise((resolve, reject) => { let lineCount = 0; fs.createReadStream(filePath) .on("data", (buffer) => { let idx = -1; lineCount--; // Because the loop will run once for idx=-1 do { idx = buffer.indexOf(10, idx+1); lineCount++; } while (idx !== -1); }).on("end", () => { resolve(lineCount); }).on("error", reject); }); }; |
这个解决方案的作用是它使用
我们让Node运行时搜索我们,这是在较低级别实现的,应该更快。
在我的系统上,这大约是在大文件(111 MB)上在缓冲区长度上运行
因为iojs 1.5.0有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | ubuntu@server:~$ wc logs 7342500 27548750 427155000 logs ubuntu@server:~$ time wc -l logs 7342500 logs real 0m0.180s user 0m0.088s sys 0m0.084s ubuntu@server:~$ nvm use node Now using node v0.12.1 ubuntu@server:~$ time node countlines.js logs 7342500 real 0m2.559s user 0m2.200s sys 0m0.340s ubuntu@server:~$ nvm use iojs Now using node iojs-v1.6.2 ubuntu@server:~$ time iojs countlines2.js logs 7342500 real 0m1.363s user 0m0.920s sys 0m0.424s ubuntu@server:~$ cat countlines.js var i; var count = 0; require('fs').createReadStream(process.argv[2]) .on('data', function(chunk) { for (i=0; i < chunk.length; ++i) if (chunk[i] == 10) count++; }) .on('end', function() { console.log(count); }); ubuntu@server:~$ cat countlines2.js var i; var count = 0; require('fs').createReadStream(process.argv[2]) .on('data', function(chunk) { var index = -1; while((index = chunk.indexOf(10, index + 1)) > -1) count++ }) .on('end', function() { console.log(count); }); ubuntu@server:~$ |
如果使用节点8及更高版本,则可以使用此async / await模式
1 2 3 4 5 6 7 8 9 10 11 12 13 | const util = require('util'); const exec = util.promisify(require('child_process').exec); async function fileLineCount({ fileLocation }) { const { stdout } = await exec(`cat ${fileLocation} | wc -l`); return parseInt(stdout); }; // Usage async someFunction() { const lineCount = await fileLineCount({ fileLocation: 'some/file.json' }); } |
1 2 3 4 5 6 | var fs=require('fs'); filename=process.argv[2]; var data=fs.readFileSync(filename); var res=data.toString().split(' ').length; console.log(res-1);` |
我发现的最佳解决方案是使用promises,async和await。这也是一个如何等待履行承诺的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #!/usr/bin/env node const fs = require('fs'); const readline = require('readline'); function main() { function doRead() { return new Promise(resolve => { var inf = readline.createInterface({ input: fs.createReadStream('async.js'), crlfDelay: Infinity }); var count = 0; inf.on('line', (line) => { console.log(count + ' ' + line); count += 1; }); inf.on('close', () => resolve(count)); }); } async function showRead() { var x = await doRead(); console.log('line count: ' + x); } showRead(); } main(); |
有一个名为count-lines-in-file的npm模块。我一直在使用它的小(<1000行)文件,它到目前为止工作得很好。
您还可以使用indexOf():
1 2 3 | var index = -1; var count = 0; while ((index = chunk.indexOf(10, index + 1)) > -1) count++; |
这是没有那么多嵌套的另一种方式。
1 2 3 4 5 6 7 | var fs = require('fs'); filePath = process.argv[2]; fileBuffer = fs.readFileSync(filePath); to_string = fileBuffer.toString(); split_lines = to_string.split(" "); console.log(split_lines.length-1); |