0

ノードストリームを使用していくつかのログファイルを処理する小さなパーサーを作成しています (実際には io.js ですが、それは問題ではないと思います)。

unshiftのドキュメントの例に従って、ヘッダーを解析しています。バッファを正常に分割してヘッダーを取得できますが、呼び出すとすぐにstream.unshift、ヘッダー文字列と残りの文字列が連結されているように見えます。

この質問のサンプルコードを設定する際に、ファイルベースのストリームを見ているときにこの動作が発生することがわかりました。文字列ベースのストリームを使用すると、ファイルに文字列とまったく同じテキストが含まれていても、問題は発生しません。

空白文字をオンにしたテキスト エディターでファイルがどのように表示されるかを次に示します (比較用)。 サンプル ログ ファイルのテキスト エディタ出力

なぜこれが起こっているのかを理解するための支援が必要です。

var StringDecoder = require('string_decoder').StringDecoder;

// setup string based stream in fake_stream
    var Stream = require('stream');
    var fake_file = 'FILE_TYPE:SOME-HEADER-DATE\r\n'
                  + 'HEADER_END\r\n'
                  + '1234|logged data|1|2|3|4|5|some other logged data\x1E\r\n'
                  + '1235|logged data|1|2|3|4|5|some other logged data\x1E\r\n'
                  + '1236|logged data|1|2|3|4|5|some other logged data\x1E\r\n'
    var fake_stream = new Stream.Readable();
    fake_stream.push(new Buffer(fake_file, 'utf8'));
    fake_stream.push(null);


// setup file based stream in file_stream
// the file minimal_test_log.glf has the text shown above (with the control characters unescaped)
    var fs = require('fs');
    var file = 'C:\\Some\\Path\\To\\minimal_test_log.glf';
    var file_stream = fs.createReadStream(file);



// WHY AM I GETTING DIFFERENT RESULTS HERE?

    parseHeader(file_stream, function(err, header, stream) {
        console.log('processing file_stream: ' + header.length);
        // RESULTS:  processing file_stream: 184
        // this results in the both parts concatenated without the HEADER_END/r/n
    });

    parseHeader(fake_stream, function(err, header, stream) {
        console.log('processing fake_stream: ' + header.length);
        // RESULTS:  processing fake_stream: 28
        // these results are what i would expect, everything before HEADER_END
    });



// Slightly modified example found at https://iojs.org/api/stream.html#stream_readable_unshift_chunk

function parseHeader(stream, callback) {
    stream.on('error', callback);
    stream.on('readable', onReadable);

    var decoder = new StringDecoder('utf8');
    var header = '';

    function onReadable() {

        var chunk, buf, remaining;
        var header_boundary = /HEADER_END\r\n/g;

        while (null !== (chunk = stream.read())) {

            var str = decoder.write(chunk);

            if (str.match(header_boundary)) {

                var split = str.split(header_boundary);
                header += split.shift();

                remaining = split.join('');
                buf = new Buffer(remaining, 'utf8');

                if (buf.length) {
                    stream.unshift(buf);
                }

                // the header length is different starting at this point

                stream.removeListener('error', callback);
                stream.removeListener('readable', onReadable);

                callback(null, header, stream);

            } else {
                header += str;
            }
        }
    }
}

4

1 に答える 1

0

したがって、カウンターを追加するonReadableと、2 回呼び出されていることがわかります。header宣言のスコープは よりも広いためonReadable、 に格納されていたものはすべて保持されheaderます。onReadable関数 の 2 回目header_boundaryは一致せず、if ステートメントが句に短絡しelse、残りのログが に追加されheaderます。

イベントに関するドキュメントreadableを読み直し、そのことを知りました

内部バッファが空になると、readable使用可能なデータが増えると、イベントが再び発生します。

を呼び出すと、それが起こっていると思いますstream.unshift(buf);readableを使用してデータをストリームに戻すたびに、2 番目のイベントが発生しunshiftます。

2 番目のreadableイベントは、「ファイル」ベースのストリームと「文字列」ベースのストリームの両方に対して発生します。ただし、タイミングが少し異なるようです。「文字列」ベースのストリームでは、2 番目のreadableイベントが発生するまでに、コールバックがすでに実行されています。「ファイル」ベースのストリームでは、readableイベントが発生し、余分なデータがheader変数に追加されるまで、コールバックは実行されません。

ストリーム間でタイミングが異なる理由はよくわかりませんが、作業を続けるには十分です。

于 2015-03-09T16:05:54.417 に答える