141

Javascript/Node.js (私は Cube を使用しています) で大きな (5 ~ 10 Gb) ログファイルの解析を行う必要があります。

ログラインは次のようになります。

10:00:43.343423 I'm a friendly log message. There are 5 cats, and 7 dogs. We are in state "SUCCESS".

各行を読み取り、いくつかの解析を行い (例:と を取り除く) 5、JS クライアントを使用してこのデータを Cube ( https://github.com/square/cube )に送り込む必要があります。7SUCCESS

まず、Nodeでファイルを1行ずつ読み取る標準的な方法は何ですか?

オンラインでかなり一般的な質問のようです:

多くの回答は、一連のサードパーティ モジュールを指しているようです。

ただし、これはかなり基本的なタスクのように思えます-確かに、標準ライブラリ内にテキストファイルを1行ずつ読み取る簡単な方法がありますか?

次に、各行を処理する必要があります (たとえば、タイムスタンプを Date オブジェクトに変換し、有用なフィールドを抽出します)。

スループットを最大化して、これを行う最善の方法は何ですか? 各行の読み取り、またはキューブへの送信のいずれかでブロックされない方法はありますか?

第三に、文字列分割を使用していると推測しています.JSのcontains (IndexOf != -1?) に相当するものは、正規表現よりもはるかに高速になりますか? Node.js で大量のテキスト データを解析した経験のある人はいますか?

乾杯、ビクター

4

12 に答える 12

236

ストリームを使用して、非常に大きなファイル (GBS) を 1 行ずつ解析するソリューションを探しました。サードパーティのライブラリとサンプルはすべて、ファイルを行ごとに処理しない ( 1 、 2 、 3 、 4 など) か、ファイル全体をメモリに読み込むため、私のニーズには合いませんでした。

次のソリューションは、ストリームとパイプを使用して、非常に大きなファイルを 1 行ずつ解析できます。テストには、17.000.000 レコードの 2.1 GB ファイルを使用しました。RAM の使用量は 60 MB を超えませんでした。

まず、event-streamパッケージをインストールします。

npm install event-stream

それで:

var fs = require('fs')
    , es = require('event-stream');

var lineNr = 0;

var s = fs.createReadStream('very-large-file.csv')
    .pipe(es.split())
    .pipe(es.mapSync(function(line){

        // pause the readstream
        s.pause();

        lineNr += 1;

        // process line here and call s.resume() when rdy
        // function below was for logging memory usage
        logMemoryUsage(lineNr);

        // resume the readstream, possibly from a callback
        s.resume();
    })
    .on('error', function(err){
        console.log('Error while reading file.', err);
    })
    .on('end', function(){
        console.log('Read entire file.')
    })
);

ここに画像の説明を入力

それがどうなるか教えてください!

于 2014-05-16T13:12:54.073 に答える
82

組み込みのreadlineパッケージを使用できます。こちらのドキュメントを参照してください。stream を使用して、新しい出力ストリームを作成します

var fs = require('fs'),
    readline = require('readline'),
    stream = require('stream');

var instream = fs.createReadStream('/path/to/file');
var outstream = new stream;
outstream.readable = true;
outstream.writable = true;

var rl = readline.createInterface({
    input: instream,
    output: outstream,
    terminal: false
});

rl.on('line', function(line) {
    console.log(line);
    //Do your stuff ...
    //Then write to outstream
    rl.write(cubestuff);
});

大きなファイルは処理に時間がかかります。それが機能するかどうか教えてください。

于 2013-04-15T10:44:50.143 に答える
24

テキスト ファイルから 1,000,000 行を超える読み取りにhttps://www.npmjs.com/package/line-by-lineを使用しました。この場合、RAM の占有容量は約 50 ~ 60 メガバイトでした。

    const LineByLineReader = require('line-by-line'),
    lr = new LineByLineReader('big_file.txt');

    lr.on('error', function (err) {
         // 'err' contains error object
    });

    lr.on('line', function (line) {
        // pause emitting of lines...
        lr.pause();

        // ...do your asynchronous line processing..
        setTimeout(function () {
            // ...and continue emitting lines.
            lr.resume();
        }, 100);
    });

    lr.on('end', function () {
         // All lines are read, file is closed now.
    });
于 2016-07-11T10:58:28.657 に答える
14

Node.js ドキュメントは、Readline モジュールを使用した非常に洗練された例を提供します。

例: ファイル ストリームを 1 行ずつ読み取る

const fs = require('fs');
const readline = require('readline');

const rl = readline.createInterface({
    input: fs.createReadStream('sample.txt'),
    crlfDelay: Infinity
});

rl.on('line', (line) => {
    console.log(`Line from file: ${line}`);
});

注: crlfDelay オプションを使用して、CR LF ('\r\n') のすべてのインスタンスを単一の改行として認識します。

于 2019-08-29T04:19:26.510 に答える
2

node-byline はストリームを使用するため、巨大なファイルにはストリームを使用することをお勧めします。

日付変換にはmoment.jsを使用します。

スループットを最大化するには、ソフトウェア クラスターの使用を検討できます。ノードネイティブのクラスターモジュールを非常にうまくラップするナイスモジュールがいくつかあります。Isaacsの cluster-masterが好きです。たとえば、すべてファイルを計算する x 個のワーカーのクラスターを作成できます。

分割と正規表現のベンチマークには、benchmark.js を使用します。私は今までそれをテストしていません。ベンチマーク.jsはノードモジュールとして利用可能です

于 2013-04-15T10:49:06.723 に答える
-1

大きなファイルをテキストまたは JSON で非同期に読み取るノード モジュールを作成しました。大きなファイルでテスト済み。

var fs = require('fs')
, util = require('util')
, stream = require('stream')
, es = require('event-stream');

module.exports = FileReader;

function FileReader(){

}

FileReader.prototype.read = function(pathToFile, callback){
    var returnTxt = '';
    var s = fs.createReadStream(pathToFile)
    .pipe(es.split())
    .pipe(es.mapSync(function(line){

        // pause the readstream
        s.pause();

        //console.log('reading line: '+line);
        returnTxt += line;        

        // resume the readstream, possibly from a callback
        s.resume();
    })
    .on('error', function(){
        console.log('Error while reading file.');
    })
    .on('end', function(){
        console.log('Read entire file.');
        callback(returnTxt);
    })
);
};

FileReader.prototype.readJSON = function(pathToFile, callback){
    try{
        this.read(pathToFile, function(txt){callback(JSON.parse(txt));});
    }
    catch(err){
        throw new Error('json file is not valid! '+err.stack);
    }
};

ファイルを file-reader.js として保存し、次のように使用します。

var FileReader = require('./file-reader');
var fileReader = new FileReader();
fileReader.readJSON(__dirname + '/largeFile.json', function(jsonObj){/*callback logic here*/});
于 2016-06-25T08:35:02.913 に答える