将node.js流写入字符串变量

obr*_*nmd 79 javascript stream node.js

我正在攻击node.js程序,该程序捕获SMTP邮件并对邮件数据进行操作.'smtp-protocol'节点库以流形式提供邮件数据,作为node.js新手,我不知道如何将该流写入字符串变量.我目前使用该行写入stdout:

__PRE__

正如我所说,我需要将此流数据写入字符串变量,然后在流结束后我将使用它.

非常感谢!

Tom*_*rae 61

希望这比上面的答案(现在有一个断开的链接)更有用.

另请注意,字符串连接不是收集字符串部分的有效方法,但它用于简单(也许您的代码不关心效率)

var string = '';
stream.on('data',function(data){
  string += data.toString();
  console.log('stream data ' + part);
});

stream.on('end',function(){
  console.log('final output ' + string);
});
Run Code Online (Sandbox Code Playgroud)

  • 这不对.如果缓冲区位于多字节代码点的中间,则toString()将收到格式错误的utf-8,并且最终会在字符串中出现一堆 . (11认同)
  • 什么是收集字符串部分的更有效方法?TY (4认同)
  • @alextgordon 是对的。在一些非常罕见的情况下,当我有很多块时,我会在块的开头和结尾处得到这些。特别是当边缘有俄罗斯符号时。因此,正确的做法是连接块并最终转换它们,而不是转换块并连接它们。就我而言,请求是使用 request.js 使用默认编码从一项服务向另一项服务发出的 (3认同)
  • 您可以使用缓冲区https://docs.nodejitsu.com/articles/advanced/buffers/how-to-use-buffers,但这实际上取决于您的使用情况. (2认同)
  • 使用一个字符串数组,将每个新块附加到数组,并在末尾调用数组上的"join("")`. (2认同)

Ric*_*cky 56

以上都不适合我.我需要使用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));
  });
Run Code Online (Sandbox Code Playgroud)

  • 这实际上是最干净的方式;) (6认同)
  • 效果很好。只是注意:如果您想要正确的字符串类型,则需要从concat()调用中对生成的Buffer对象调用.toString() (5认同)
  • 事实证明,实际的最佳答案来晚了:/sf/answers/4435308041/ (2认同)

Mar*_*des 51

另一种方法是将流转换为promise(请参阅下面的示例)并使用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)
Run Code Online (Sandbox Code Playgroud)

  • **这应该是最好的答案。**恭喜您制作出唯一能够使所有事情都正确的解决方案,其中(1)将这些块存储为Buffer,最后只调用`.toString(“ utf8”)`,以避免如果在多字节字符的中间拆分块,则解码失败的问题;(2)实际错误处理;(3)将代码放入函数中,以便可以重用,而不是复制粘贴;(4)使用Promises,以便可以“等待”功能;(5)与某些npm库不同,不会拖入一百万个依赖项的小代码;(6)ES6语法和现代最佳实践。 (5认同)
  • 在我使用当前最佳答案作为提示想出基本相同的代码后,我注意到上面的代码可能会失败,并显示“Uncaught TypeError [ERR_INVALID_ARG_TYPE]:“list[0]”参数必须是 Buffer 或 Uint8Array 的实例。如果流生成“string”块而不是“Buffer”,则接收到类型“string”。使用 `chunks.push(Buffer.from(chunk))` 应该适用于 `string` 和 `Buffer` 块。 (4认同)
  • 您必须在异步函数中调用streamtostring函数。为了避免这种情况,您还可以执行 `streamToString(stream).then(function(response){//Do What you Want with response});` (3认同)
  • 事实证明,实际的最佳答案来晚了:/sf/answers/4435308041/ (3认同)
  • 为什么不将 chunks 数组移至 Promise 中? (2认同)

Tra*_*nov 37

你怎么看待这件事 ?

// lets have a ReadableStream as a stream variable

const chunks = [];

for await (let chunk of stream) {
    chunks.push(chunk)
}

const buffer  = Buffer.concat(chunks);
const str = buffer.toString("utf-8")

Run Code Online (Sandbox Code Playgroud)

  • 必须使用 `chunks.push(Buffer.from(chunk));` 才能使其与字符串块一起使用。 (4认同)
  • 这是与最佳答案相同的现代版本。Node.js/JS 变化很快。我建议使用这个而不是最受好评的一个,因为它更干净并且不会让用户必须触摸事件。 (3认同)
  • 哇,这看起来非常整洁!这有什么问题吗(除了上面评论中提到的问题)?它可以处理错误吗? (2认同)

Con*_*Del 30

关键是要使用这两个Stream事件:

  • 事件:'数据'
  • 事件:'结束'

因为data您应该将数据数据收集到Buffer(如果是二进制)或字符串中.

因为end您应该使用完成的缓冲区调用回调,或者如果您可以内联它并使用Promises库返回.

  • 说明答案的几行代码比仅指向API的链接更可取.不要不同意答案,只是不要相信它足够完整. (132认同)
  • 使用较新的node.js版本,此方法会更干净:http://stackoverflow.com/a/35530615/271961 (2认同)

dre*_*lse 19

我通常使用这个简单的函数将流转换为字符串:

function streamToString(stream, cb) {
  const chunks = [];
  stream.on('data', (chunk) => {
    chunks.push(chunk.toString());
  });
  stream.on('end', () => {
    cb(chunks.join(''));
  });
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

let stream = fs.createReadStream('./myFile.foo');
streamToString(stream, (data) => {
  console.log(data);  // data is now my string variable
});
Run Code Online (Sandbox Code Playgroud)

  • 当多字节字符在块之间分割时,存在一种边缘情况。这会导致原始字符被两个不正确的字符替换。 (2认同)

est*_*ani 14

还有另一个使用 Promise 的字符串:

function getStream(stream) {
  return new Promise(resolve => {
    const chunks = [];

    # Buffer.from is required if chunk is a String, see comments
    stream.on("data", chunk => chunks.push(Buffer.from(chunk)));
    stream.on("end", () => resolve(Buffer.concat(chunks).toString()));
  });
}

Run Code Online (Sandbox Code Playgroud)

用法:

const stream = fs.createReadStream(__filename);
getStream(stream).then(r=>console.log(r));
Run Code Online (Sandbox Code Playgroud)

.toString()如果需要,删除与二进制数据一起使用的 。

更新:@AndreiLED 正确指出这有字符串问题。我无法获得返回带有我拥有的节点版本的字符串的流,但api指出这是可能的。


Eri*_*zen 11

使用 Node.js 内置的StreamConsumers.text最简单:

import { text } from 'node:stream/consumers';
import { Readable } from 'node:stream';

const readable = Readable.from('Hello world from consumers!');
const string = await text(readable);
Run Code Online (Sandbox Code Playgroud)


Seb*_* J. 7

从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);
})
Run Code Online (Sandbox Code Playgroud)


flo*_*ori 6

Streams没有一个简单的.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);
});
Run Code Online (Sandbox Code Playgroud)


vde*_*nne 5

我这样使用比较幸运:

let string = '';
readstream
    .on('data', (buf) => string += buf.toString())
    .on('end', () => console.log(string));
Run Code Online (Sandbox Code Playgroud)

我使用节点v9.11.1,这readstream是回调的响应http.get


Vil*_*lle 5

使用流行的(每周下载量超过 500 万次)和轻量级的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
})();
Run Code Online (Sandbox Code Playgroud)