Node.js:计算文件中的行数

hex*_*ide 26 javascript node.js

我有大文本文件,范围介于30MB和之间10GB.如何计算文件中使用的行数Node.js

我有这些限制:

  • 整个文件不需要写入内存
  • 执行任务不需要子进程

And*_*rov 29

不使用wc的解决方案:

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);
  });
Run Code Online (Sandbox Code Playgroud)

它的速度较慢,但​​不是那么多 - 140M +文件的0.6s包括node.js加载和启动时间

>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
Run Code Online (Sandbox Code Playgroud)

  • 10是"新行"字符的ascii代码.为了更好的可读性,你可以在几行之前使用`const LINE_FEED ='\n'.charCodeAt(0)`然后`if(chunk [i] == LINE_FEED)count ++ (4认同)
  • 你的基准测试不是很有说服力,因为你在一个没有*结构化成行的文件上运行它,因此不能代表OP想要处理的文件类型.行分析`if(chunk [i] == 10)count ++;`在分析文本文件时比在分析二进制视频文件时更频繁地执行. (3认同)
  • 对不起,请问“ chunk [i] == 10”是什么意思?我猜想如果块等于10,这是换行符,但是为什么要与数字10进行比较? (2认同)
  • 您的实施差一分。例如,如果您的文件有 2 行,那么它只有 1 个“换行符”,因此您的脚本将记录“1”。 (2认同)

Men*_*ual 25

您可以在评论建议使用时执行此操作 wc

var exec = require('child_process').exec;

exec('wc /path/to/file', function (error, results) {
    console.log(results);
});
Run Code Online (Sandbox Code Playgroud)

  • `wc`是一个特定于bash的命令,可能无法在Windows环境中工作 (12认同)
  • 如果您喜欢这样做,请尝试`sed -n'$ ='/ path/to/file`它只返回行数,您可以在其上应用函数`parseInt`来获取您的数字. (3认同)
  • `wc -l` 只计算行数 (2认同)
  • `parseInt(execSync('wc -l &lt;​​ /path/to/file').toString().trim())` (2认同)

Emi*_*röm 15

我们可以使用indexOf让VM找到换行符:

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);
  });
};
Run Code Online (Sandbox Code Playgroud)

这个解决方案的作用是找到第一个换行符的位置.indexOf.它递增lineCount,然后它找到下一个位置.第二个参数.indexOf告诉从哪里开始寻找换行符.这样我们就跳过缓冲区的大块.while循环将为每个换行符加一次.

我们让Node运行时搜索我们,这是在较低级别实现的,应该更快.

在我的系统上,这大约是for在大文件(111 MB)上运行缓冲区长度的循环的两倍.

  • 与其他人在此展示相比,这是最好的解决方案! (2认同)

小智 6

var fs=require('fs');
filename=process.argv[2];
var data=fs.readFileSync(filename);
var res=data.toString().split('\n').length;
console.log(res-1);`
Run Code Online (Sandbox Code Playgroud)

  • 虽然此代码片段可以解决问题,但[包括解释](https://meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers)确实有助于提高帖子的质量。请记住,您是在为将来的读者回答问题,而那些人可能不知道您建议代码的原因。还请尽量不要在代码中添加解释性注释,这会降低代码和解释的可读性! (6认同)
  • 该解决方案需要将文件加载到内存中。我建议不要这么做。使用“wc”的答案不会,因为“wc”已针对流式传输文件进行了优化。 (3认同)
  • 与一年前发布相同内容的 [Alan Viars](/sf/answers/2260077571/) 相比,这个答案也没有添加任何有价值的内容。 (2认同)
  • 该问题明确指出文件的大小范围为 30MB 到 10GB。该解决方案在处理之前将整个文件读入内存。这可能会导致代码崩溃,因为 JavaScript 会耗尽内存 (2认同)

und*_*Zen 5

从iojs 1.5.0开始,有一种Buffer#indexOf()方法可以用来与Andrey Sidorov的答案进行比较:

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:~$ 
Run Code Online (Sandbox Code Playgroud)


Ala*_*ars 5

这是另一种没有这么多嵌套的方法。

var fs = require('fs');
filePath = process.argv[2];
fileBuffer =  fs.readFileSync(filePath);
to_string = fileBuffer.toString();
split_lines = to_string.split("\n");
console.log(split_lines.length-1);
Run Code Online (Sandbox Code Playgroud)

  • 对于 10gb 的文件,至少可以说这不是非常高效。 (5认同)