2015-03-09 1 views
0

Я пишу небольшой парсер для обработки некоторых файлов журналов с использованием потоков узлов (на самом деле, io.js, но я не думаю, что это важно).Разбор заголовка из потока на основе файлов дает неожиданные результаты

Я следую примеру в docs for unshift, чтобы разобрать заголовок. Я могу успешно разделить буфер и захватить заголовок, но как только я вызываю stream.unshift, он, похоже, конкатенирует строку заголовка и оставшуюся строку.

При создании некоторого примера кода для этого вопроса я узнал, что это происходит, когда я смотрю на поток, основанный на файле. Всякий раз, когда я использую поток на основе строк, проблема не возникает, хотя файл имеет тот же самый текст, что и строка.

Вот что файл выглядит как в моем текстовом редакторе с пробельными символами включены, (для сравнения): text editor output of example log file

мне нужна помощь понять, почему это происходит.

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

Поэтому добавление счетчика к onReadable показывает, что она вызывается дважды. Поскольку объем заявления header шире, чем onReadable, он сохраняет все, что хранилось в header. Во второй раз через функцию onReadableheader_boundary не будет соответствовать, а оператор if - короткое замыкание в положение else, добавив остальную часть журнала в header.

Я перечитал docs on the readable event, и узнал, что

После того, как внутренний буфер израсходована, readable событие будет стрелять снова, когда больше данных доступно

Я считаю, что это то, что происходит, когда я позвоните по телефону stream.unshift(buf);. Второе событие readable запускается всякий раз, когда я добавляю данные обратно в поток с помощью unshift.

Второе событие readable запускается как для основанных на файле файлов, так и для потоков, основанных на строках. Кажется, однако, что время между ними немного отличается. В потоке, основанном на строках, к моменту запуска второго события readable обратный вызов уже выполнен. В потоке, основанном на файле, обратный вызов не выполняется до тех пор, пока не произойдет событие readable, и дополнительные данные были добавлены к переменной header.

Я не совсем понял, почему время между разными потоками отличается, но это дает мне достаточно для продолжения моей работы.

Смежные вопросы