我正在编写一个小的解析器来处理一些使用节点流的日志文件(io.js,实际上,但我不认为这很重要)。
我按照docs for 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;
}
}
}
}
答案 0 :(得分:0)
因此,向onReadable
添加一个计数器会显示它被调用两次。由于header
声明的范围比onReadable
更宽,因此它会保留header
中存储的内容。第二次通过onReadable
函数时,header_boundary
将不匹配,并且if语句与else
子句短路,将日志的其余部分追加到header
。
我重读了docs on the readable
event,并了解了
内部缓冲区耗尽后,当有更多数据可用时,
readable
事件将再次触发
我相信当我致电stream.unshift(buf);
时会发生这种情况。每当我使用readable
将数据添加回流中时,都会触发第二个unshift
事件。
第二个readable
事件正在针对"文件"基于和#34;字符串"基于溪流。然而,似乎他们之间的时间有点不同。在"字符串"基于流,到第二个readable
事件被触发时,回调已经执行。在"文件"基于流,在readable
事件触发并且额外数据已附加到header
变量之后才会执行回调。
我还没有弄清楚为什么流之间的时间不同,但它足以让我继续我的工作。