2016-06-29 4 views
11

Я уже узнал, что readline может использоваться для чтения файла по строкам, например.Эффективно читайте файл по строкам в узле

readline 
    .createInterface({input: fs.createReadStream('xxx')}) 
    .on('line', (line) => { apply_regexp_on_line }) 
    .on('close',() => { report_all_regexps }); 

Однако, это довольно медленно, так как я сравнил производительность grep и JavaScript регулярных выражений, а последний имеет более высокую производительность на регулярных выражений, которые я тестировал. (см. benchmark) Итак, я думаю, что я должен обвинять асинхронный readline узла.

В моей ситуации мне вообще неинтересно, я просто должен использовать быстрое регулярное выражение JavaScript для обработки очень больших файлов журнала (обычно 1-2 ГБ, иногда до 10 ГБ). Каков наилучший способ сделать это? Меня беспокоит только скорость.

Бонусные баллы: некоторые файлы журналов являются gzipped, поэтому мне нужно их распаковать. Если кто-то может порекомендовать мне быстрый линейный считыватель как для обычного текста, так и для gzipped-текста, я был бы очень благодарен.

+0

Не знаете, что делает 'apply_regexp_on_line', но можно ли использовать программу unix' sed' для выполнения ваших строк? Это довольно быстро. Вероятно, можно написать быстрый и простой сценарий оболочки, чтобы делать распаковку и seding. –

+0

См. Ссылку в вопросе. 'sed' не так быстро, как JavaScript. В основном 'apply_regexp_on_line' будет захватывать некоторый текст в файле журнала с помощью regexp и хранить его, а' report_all_regexps' будет передавать захваченный текст в заданном формате. – xis

+0

благодарит за информацию. Не ожидал, что 'sed' будет медленнее, чем регулярное выражение javascript! поднял проголосовавшую тему && добавил в избранное. Я тоже хочу знать решение. –

ответ

1

Как это держится против ваших данных?

// module linegrep.js 
'use strict'; 
var through2 = require('through2'); 
var StringDecoder = require('string_decoder').StringDecoder 

function grep(regex) { 
    var decoder = new StringDecoder('utf8'), 
     last = "", 
     lineEnd = /\r?\n/; 

    var stream = through2({}, function transform(chunk, enc, cb) { 
     var lines = decoder.write(last + chunk).split(lineEnd), i; 
     last = lines.pop(); 
     for (i = 0; i < lines.length; i++) { 
      if (regex.test(lines[i])) this.push(lines[i]); 
     } 
     cb(); 
    }, function flush(cb) { 
     if (regex.test(last)) this.push(last); 
     cb(); 
    }); 
    stream._readableState.objectMode = true; 
    return stream; 
} 

module.exports = grep; 

и

// index.js 

'use strict'; 
var fs = require('fs'); 
var zlib = require('zlib'); 
var grep = require('./linegrep'); 

function grepFile(filename, regex) { 
    var rstream = fs.createReadStream(filename, {highWaterMark: 172 * 1024}); 
    if (/\.gz$/.test(filename)) rstream = rstream.pipe(zlib.createGunzip()); 
    return rstream 
     .pipe(grep(regex)); 
} 

// ------------------------------------------------------------------------- 

var t = Date.now(), mc = 0; 
grepFile('input.txt', /boot\.([a-z]+)_head\./).on('data', function (line) { 
    mc++; 
    console.log(line); 
}).on('end', function() { 
    console.log(mc + " matches, " + (Date.now() - t) + " ms"); 
}); 

Это превращает поток файла в объект потока строк, отображает их через регулярные выражения и возвращает только совпадающие строки.

+0

Меньше, чем мой код, который использует 'fs.readFileSync (filename) .toString(). Split ('\ n'). ForEach ((line) => {regexp. exec (/ regexp /);}); ' – xis

+0

Хм, это позор.С положительной стороны, он может иметь дело с произвольно большими входными файлами. – Tomalak

+0

Ну, это правильно. Я предполагаю, что система событий «node» является причиной того, что она медленная. В обход события произойдет намного быстрее код. – xis

Смежные вопросы