Узел записи.JS поток в строковую переменную
Я взламываю узел.JS программа, которая захватывает SMTP почты и действует на почтовых данных. Библиотека узлов 'smtp-protocol' предоставляет почтовые данные в реальном времени как поток, так и как узел.JS новичок я не уверен, как записать этот поток в строковую переменную. В настоящее время я пишу его в stdout, используя строку:
stream.pipe(process.stdout, { end : false });
Как я уже сказал, мне нужно получить эту запись данных потока в строковую переменную, которую я буду использовать после завершения потока.
сильно поможет спасибо!
12 ответов:
ключ должен использовать эти два событий потока:
- событие: 'сведения'
- событие: 'конец'
на
stream.on('data', ...)вы должны собрать свои данные в буфер (если это двоичный) или в строку.на
on('end', ...)вы должны вызвать обратный вызов с завершенным буфером, или если вы можете встроить его и использовать return с помощью библиотеки обещаний.
надеюсь, что это более полезно, чем приведенный выше ответ (который теперь имеет сломанную ссылку).
также обратите внимание, что конкатенация строк не является эффективным способом сбора строковых частей, но она используется для простоты (и, возможно, ваш код не заботится об эффективности)
var string = '' stream.on('readable',function(buffer){ var part = buffer.read().toString(); string += part; console.log('stream data ' + part); }); stream.on('end',function(){ console.log('final output ' + string); });
ни один из выше работал для меня. Мне нужно было использовать объект Buffer:
const chunks = []; readStream.on("data", function (chunk) { chunks.push(chunk); }); // Send the buffer or you can put it into a var readStream.on("end", function () { res.send(Buffer.concat(chunks)); });
обычно я использую эту простую функцию для преобразования потока в строку:
function streamToString(stream, cb) { const chunks = []; stream.on('data', (chunk) => { chunks.push(chunk.toString()); }); stream.on('end', () => { cb(chunks.join('')); }); }пример использования:
let stream = fs.createReadStream('./myFile.foo'); streamToString(stream, (data) => { console.log(data); // data is now my string variable });
другой способ-преобразовать поток в обещание (см. пример ниже) и использовать
then(илиawait) для присвоения переменной разрешенного значения.function streamToString (stream) { const chunks = [] return new Promise((resolve, reject) => { stream.on('data', chunks.push) stream.on('error', reject) stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8'))) }) } const result = await streamToString(stream)
от nodejs документация вы должны сделать это-всегда помните строку, не зная, что кодировка-это просто куча байтов:
var readable = getReadableStreamSomehow(); readable.setEncoding('utf8'); readable.on('data', function(chunk) { assert.equal(typeof chunk, 'string'); console.log('got %d characters of string data', chunk.length); })
мне повезло больше, используя вот так:
let string = ''; readstream .on('data', (buf) => string += buf.toString()) .on('end', () => console.log(string));Я использую узел
v9.11.1иreadstreamответ отhttp.getобратный.
самым чистым решением может быть использование пакета "string-stream", который преобразует поток в строку с обещанием.
const streamString = require('stream-string') streamString(myStream).then(string_variable => { // myStream was converted to a string, and that string is stored in string_variable console.log(string_variable) }).catch(err => { // myStream emitted an error event (err), so the promise from stream-string was rejected throw err })
Как насчет чего-то вроде редуктора потока ?
вот пример использования классов ES6, как использовать один.
var stream = require('stream') class StreamReducer extends stream.Writable { constructor(chunkReducer, initialvalue, cb) { super(); this.reducer = chunkReducer; this.accumulator = initialvalue; this.cb = cb; } _write(chunk, enc, next) { this.accumulator = this.reducer(this.accumulator, chunk); next(); } end() { this.cb(null, this.accumulator) } } // just a test stream class EmitterStream extends stream.Readable { constructor(chunks) { super(); this.chunks = chunks; } _read() { this.chunks.forEach(function (chunk) { this.push(chunk); }.bind(this)); this.push(null); } } // just transform the strings into buffer as we would get from fs stream or http request stream (new EmitterStream( ["hello ", "world !"] .map(function(str) { return Buffer.from(str, 'utf8'); }) )).pipe(new StreamReducer( function (acc, v) { acc.push(v); return acc; }, [], function(err, chunks) { console.log(Buffer.concat(chunks).toString('utf8')); }) );
это сработало для меня и основано на узел v6.7. 0 docs:
let output = ''; stream.on('readable', function() { let read = stream.read(); if (read !== null) { // New stream data is available output += read.toString(); } else { // Stream is now finished when read is null. // You can callback here e.g.: callback(null, output); } }); stream.on('error', function(err) { callback(err, null); })
С помощью довольно популярны
stream-buffersпакета который у вас, вероятно, уже есть в ваших зависимостях проекта, это довольно просто:// imports const { WritableStreamBuffer } = require('stream-buffers'); const { promisify } = require('util'); const { createReadStream } = require('fs'); const pipeline = promisify(require('stream').pipeline); // sample stream let stream = createReadStream('/etc/hosts'); // pipeline the stream into a buffer, and print the contents when done let buf = new WritableStreamBuffer(); pipeline(stream, buf).then(() => console.log(buf.getContents().toString()));
Comments