2016-06-29 15 views
11

Dowiedziałem się już, że readline może służyć do odczytu linii pliku po linii, np.Sprawnie odczytywany plik wiersz po wierszu w węźle

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

Jest to jednak dość wolno, bo w porównaniu wydajności grep i JavaScript regexp, a drugi ma lepsze osiągi na wyrażeniach regularnych testowałem. (patrz benchmark) Tak myślę, że muszę winić węzeł async readline.

W mojej sytuacji nie obchodzi mnie wcale asynchronizacja, po prostu potrzebuję wykorzystać szybkie wyrażenie regularne z JavaScript do przetwarzania bardzo dużych plików dziennika (zazwyczaj 1-2 GB, czasami nawet do 10 GB). Jaki jest najlepszy sposób na zrobienie tego? Moją jedyną troską jest szybkość.

Dodatkowe punkty: niektóre pliki dzienników są spakowane gzipem, więc muszę je rozpakować. Jeśli ktoś może polecić mi szybki czytnik line-by-line dla zwykłego tekstu i gzipowanego tekstu, to byłbym naprawdę doceniony.

+0

Nie jesteś pewien, co 'apply_regexp_on_line' ma, ale czy możliwe jest użycie programu' uni' '' '' '' '' '' '' '' '' '' '' '' 'sed"? Jest dość szybki. Prawdopodobnie można napisać szybki i łatwy skrypt powłoki do rozpakowania i sed'ing. –

+0

Zobacz odnośnik porównawczy w pytaniu. 'sed' nie jest tak szybkie jak JavaScript. Zasadniczo 'apply_regexp_on_line' przechwyci jakiś tekst w pliku dziennika za pomocą regexp i zapisze go, a' report_all_regexps' zgłosi przechwycony tekst w danym formacie. – xis

+0

dzięki za informacje. Nie spodziewałem się, że 'sed' będzie wolniejszy niż regex javascript! up głosowany temat && dodany do ulubionych. Chętnie też znam to rozwiązanie. –

Odpowiedz

1

Jak to się dzieje w stosunku do twoich danych?

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

i

// 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"); 
}); 

ta zamienia strumień plików na strumień obiektu linii, mapuje je za pośrednictwem regex i zwraca tylko wiersze ogłoszeń.

+0

Wolniej niż mój kod, który używa 'fs.readFileSync (filename) .toString(). Split ('\ n'). ForEach ((linia) => {regexp. exec (/ regexp /);}); ' – xis

+0

Hm, to wstyd.Z drugiej strony, może obsługiwać dowolnie duże pliki wejściowe. – Tomalak

+0

Cóż, to prawda. Zgaduję, że system zdarzeń 'węzeł' jest przyczyną powolności. Pomijanie zdarzenia spowodowałoby znacznie szybszy kod. – xis

Powiązane problemy