2016-06-29 2 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を責めなければならないと思います。私の状況で

は、私はちょうど非常に大きなログファイル(通常は1〜2ギガバイト、10ギガバイト時々まで)を処理するためにJavaScriptからの高速正規表現を利用するために必要な、すべての非同期を気にしません。これを行う最善の方法は何ですか?私の唯一の懸念はスピードです。

ボーナスポイント:いくつかのログファイルはgzipで圧縮されているため、圧縮解除する必要があります。誰かが、プレーンテキストとgzippedテキストの両方に高速な行単位の読者を勧めてもらえれば、本当に感謝しています。

+0

'apply_regexp_on_line'とは何でしょうか、あなたの文字列の置換を行うために' sed'プログラムを使うことは可能でしょうか?それはかなり速いです。おそらく、解凍とsed'ingを行うための素早く簡単なシェルスクリプトを書くことができます。 –

+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

関連する問題