节点文件行计数

时间:2017-01-03 08:24:40

标签: node.js asynchronous

我得到的反馈是,此节点功能在获取文件的行数方面存在性能问题,但无法确定详细信息。

function countFileLines(filePath){
  return new Promise((resolve, reject) => {
  let lineCount = 0;
  fs.createReadStream(filePath)
    .on("data", (buffer) => {
      buffer.forEach((chunk) => {
        if (chunk === 10) lineCount++;
      });
    }).on("end", () => {
      resolve(lineCount);
    }).on("error", reject);
  });
};

在Node中获取文件的行数是否有更高效的方法?

2 个答案:

答案 0 :(得分:3)

function countFileLines(filePath){
  return new Promise((resolve, reject) => {
  let lineCount = 0;
  let i = 0;
  fs.createReadStream(filePath)
    .on("data", (buffer) => {
      for (i = 0; i < buffer.length; ++i) {
        if (buffer[i] == 10) lineCount++;
      }
    }).on("end", () => {
      resolve(lineCount);
    }).on("error", reject);
  });
};

进行比较:

原文:node index.js 2.38s user 0.29s system 98% cpu 2.713 total

修改:node index2.js 0.18s user 0.04s system 96% cpu 0.225 total

答案 1 :(得分:1)

我只能推测,但是buffer.forEach调用一个函数并对每个字节进行比较可能是个问题。考虑使用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);
    });
};

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

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

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