Как мне прочитать содержимое потока Node.js в строковую переменную?
Я взломал программу Node, которая использует smtp-protocol
для захвата писем SMTP и обработки почтовых данных. Библиотека предоставляет данные почты в виде потока, и я не знаю, как передать их в строку.
В настоящее время я пишу это в стандартный вывод с stream.pipe(process.stdout, { end: false })
, но, как я уже сказал, мне нужны данные потока в виде строки, которые я могу использовать после завершения потока.
Как собрать все данные из потока Node.js в строку?
Ответы
Ответ 1
Ключ заключается в использовании событий data
и end
events of a читаемого потока. Послушайте эти события:
stream.on('data', (chunk) => { ... });
stream.on('end', () => { ... });
Когда вы получите событие data
, добавьте новый фрагмент данных в буфер, созданный для сбора данных.
Когда вы получите событие end
, при необходимости преобразуйте заполненный буфер в строку. Тогда делай, что тебе нужно с этим делать.
Ответ 2
Надеюсь, что это более полезно, чем ответ выше:
var string = '';
stream.on('data',function(data){
string += data.toString();
console.log('stream data ' + part);
});
stream.on('end',function(){
console.log('final output ' + string);
});
Обратите внимание, что конкатенация строк - не самый эффективный способ сбора частей строк, но он используется для простоты (и, возможно, ваш код не заботится об эффективности).
Кроме того, этот код может привести к непредсказуемым ошибкам для текста, не относящегося к ASCII (предполагается, что каждый символ помещается в байте), но, возможно, вам это тоже не важно.
Ответ 3
Ничто из этого не помогло мне. Мне нужно было использовать объект 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));
});
Ответ 4
Другим способом будет преобразование потока в обещание (см. Пример ниже) и использование then
(или await
) для присвоения разрешенного значения переменной.
function streamToString (stream) {
const chunks = []
return new Promise((resolve, reject) => {
stream.on('data', chunk => chunks.push(chunk))
stream.on('error', reject)
stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')))
})
}
const result = await streamToString(stream)
Ответ 5
Я использую обычно эту простую функцию для преобразования потока в строку:
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
});
Ответ 6
В документации 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);
})
Ответ 7
В потоках нет простой функции .toString()
(что я понимаю), а не что-то вроде функции .toStringAsync(cb)
(которую я не понимаю).
Итак, я создал свою собственную вспомогательную функцию:
var streamToString = function(stream, callback) {
var str = '';
stream.on('data', function(chunk) {
str += chunk;
});
stream.on('end', function() {
callback(str);
});
}
// how to use:
streamToString(myStream, function(myStr) {
console.log(myStr);
});
Ответ 8
Мне повезло больше, используя вот так:
let string = '';
readstream
.on('data', (buf) => string += buf.toString())
.on('end', () => console.log(string));
Я использую узел v9.11.1
а readstream
- это ответ от обратного вызова http.get
.
Ответ 9
Простой способ с популярной (более 5 миллионов загрузок в неделю) и легкой библиотекой get-stream:
https://www.npmjs.com/package/get-stream
const fs = require('fs');
const getStream = require('get-stream');
(async () => {
const stream = fs.createReadStream('unicorn.txt');
console.log(await getStream(stream)); //output is string
})();
Ответ 10
Как насчет чего-то вроде редуктора потока?
Вот пример использования классов 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'));
})
);
Ответ 11
Самым чистым решением может быть использование пакета "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
})
Ответ 12
Это сработало для меня и основано на Node 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);
})
Ответ 13
setEncoding ( 'utf8');
Молодец Себастьян Дж. Выше.
У меня была "проблема с буфером" с несколькими строками тестового кода, которые я имел, и добавил информацию о кодировке, и это решило ее, см. Ниже.
Продемонстрировать проблему
программного обеспечения
// process.stdin.setEncoding('utf8');
process.stdin.on('data', (data) => {
console.log(typeof(data), data);
});
вход
hello world
выход
object <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64 0d 0a>
Продемонстрировать решение
программного обеспечения
process.stdin.setEncoding('utf8'); // <- Activate!
process.stdin.on('data', (data) => {
console.log(typeof(data), data);
});
вход
hello world
выход
string hello world
Ответ 14
Используя довольно популярный пакет 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()));
Ответ 15
И еще один для строк, использующих обещания:
function getStream(stream) {
return new Promise(resolve => {
const chunks = [];
stream.on("data", chunk => chunks.push(chunk));
stream.on("end", () => resolve(Buffer.concat(chunks).toString()));
});
}
Использование:
const stream = fs.createReadStream(__filename);
getStream(stream).then(r=>console.log(r));
удалите .toString()
для использования с двоичными данными, если это необходимо.