Node.js: подсчитать количество строк в файле

У меня есть большие текстовые файлы, которые находятся между 30MB и 10GB. Как подсчитать количество строк в файле с помощью Node.js?

У меня есть следующие ограничения:

  • Весь файл не нужно записывать в память
  • Для выполнения задачи не требуется дочерний процесс

Ответы

Ответ 1

без использования 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);
  });

он медленнее, но не так много, как вы могли ожидать - 0,6 с для файла 140M +, включая 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

Ответ 2

Вы можете сделать это, поскольку комментарии предполагают использование wc

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

exec('wc /path/to/file', function (error, results) {
    console.log(results);
});

Ответ 3

Вот еще один способ без так много вложенности.

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

Ответ 4

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

Ответ 5

Мы можем использовать indexOf, чтобы виртуальная машина находила символы новой строки:

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 время выполнения для нас, которое выполняется на более низком уровне и должно быть быстрее.

В моей системе это примерно в два раза быстрее, чем запуск цикла for по длине буфера в большом файле (111 МБ).

Ответ 6

так как iojs 1.5.0 существует метод Buffer#indexOf(), используя его для сравнения с ответом Андрея Сидорова:

[email protected]:~$ wc logs
  7342500  27548750 427155000 logs
[email protected]:~$ time wc -l logs 
7342500 logs

real    0m0.180s
user    0m0.088s
sys 0m0.084s
[email protected]:~$ nvm use node
Now using node v0.12.1
[email protected]:~$ time node countlines.js logs 
7342500

real    0m2.559s
user    0m2.200s
sys 0m0.340s
[email protected]:~$ nvm use iojs
Now using node iojs-v1.6.2
[email protected]:~$ time iojs countlines2.js logs 
7342500

real    0m1.363s
user    0m0.920s
sys 0m0.424s
[email protected]:~$ 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);
  });
[email protected]:~$ 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);
  });
[email protected]:~$ 

Ответ 7

Вы также можете использовать indexOf():

var index = -1;
var count = 0;
while ((index = chunk.indexOf(10, index + 1)) > -1) count++;

Ответ 8

Существует модуль npm, называемый count-lines-in-file. Я использовал его для небольших (< 1000 строк) файлов, и он отлично работал до сих пор.