如何将 Node.js 流的内容读入字符串变量?

IT技术 javascript node.js stream
2021-02-21 23:47:28

我正在破解一个smtp-protocol用于捕获 SMTP 电子邮件并处理邮件数据的 Node 程序该库以流的形式提供邮件数据,我不知道如何将其转换为字符串。

我目前正在使用 将其写入标准输出stream.pipe(process.stdout, { end: false }),但正如我所说,我需要字符串中的流数据,一旦流结束,我就可以使用它。

如何将 Node.js 流中的所有数据收集到一个字符串中?

6个回答

另一种方法是将流转换为Promise(请参阅下面的示例)并使用then(或await) 将解析的值分配给变量。

function streamToString (stream) {
  const chunks = [];
  return new Promise((resolve, reject) => {
    stream.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
    stream.on('error', (err) => reject(err));
    stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
  })
}

const result = await streamToString(stream)
您必须在异步函数中调用 streamtostring 函数。为了避免这种情况,你也可以这样做streamToString(stream).then(function(response){//Do whatever you want with response});
2021-04-17 23:47:28
事实证明,真正的最佳答案来晚了:stackoverflow.com/a/63361543/1677656
2021-04-19 23:47:28
为什么不将 chunks 数组移动到 promise 中?
2021-05-01 23:47:28
在我使用当前最佳答案作为提示想出基本相同的代码后,我注意到Uncaught TypeError [ERR_INVALID_ARG_TYPE]: The "list[0]" argument must be an instance of Buffer or Uint8Array. Received type string如果流产生string块而不是Buffer. 使用chunks.push(Buffer.from(chunk))应该适用于stringBuffer块。
2021-05-02 23:47:28
这应该是最佳答案。恭喜你产生了唯一一个让一切都正确的解决方案,(1) 将块存储为 Buffers 并且只.toString("utf8")在最后调用,以避免在多字节字符中间拆分块时出现解码失败的问题;(2) 实际错误处理;(3) 把代码放在一个函数里,可以复用,不能复制粘贴;(4) 使用 Promises 使函数可以被await-ed on;(5) 不拖入百万依赖的小代码,不像某些 npm 库;(6) ES6 语法和现代最佳实践。
2021-05-07 23:47:28

以上都不适合我。我需要使用 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));
  });
这实际上是最干净的方法;)
2021-04-20 23:47:28
效果很好。请注意:如果您想要正确的字符串类型,则需要在 concat() 调用的结果 Buffer 对象上调用 .toString()
2021-04-30 23:47:28
事实证明,真正的最佳答案来晚了:stackoverflow.com/a/63361543/1677656
2021-05-04 23:47:28
这是正确执行此操作的唯一方法
2021-05-06 23:47:28

希望这比上面的答案更有用:

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 文本产生不可预知的失败(它假定每个字符都适合一个字节),但也许您也不关心这一点。

收集弦乐部分的更有效方法是什么?
2021-04-15 23:47:28
您可以使用缓冲区docs.nodejitsu.com/articles/advanced/buffers/how-to-use-buffers但这实际上取决于您的使用。
2021-04-22 23:47:28
使用字符串数组,将每个新块附加到数组中,并join("")在最后调用数组。
2021-04-23 23:47:28
这是不对的。如果缓冲区位于多字节代码点的中途,那么 toString() 将接收格式错误的 utf-8,并且您将在字符串中得到一堆 。
2021-04-26 23:47:28
@alextgordon 是对的。在一些非常罕见的情况下,当我有很多块时,我在块的开头和结尾处得到了那些 。尤其是当边缘有俄罗斯符号时。因此,连接块并最终转换它们而不是转换块并连接它们是正确的。在我的情况下,请求是从一个服务向另一个服务发出的,带有默认编码的 request.js
2021-05-12 23:47:28

(这个答案是多年前的,当时它是最好的答案。现在下面有一个更好的答案。我没有跟上 node.js,我无法删除这个答案,因为它被标记为“在这个问题上是正确的” ”。如果你想向下点击,你想让我做什么?)

关键是使用Readable Streamdataend事件收听这些事件:

stream.on('data', (chunk) => { ... });
stream.on('end', () => { ... });

当您收到data事件时,将新的数据块添加到为收集数据而创建的缓冲区中。

收到end事件后,如有必要,将完成的 Buffer 转换为字符串。然后做你需要做的事情。

答案应该更新为不推荐使用 Promises 库,而是使用本机 Promises。
2021-04-19 23:47:28
使用较新的 node.js 版本,这更干净:stackoverflow.com/a/35530615/271961
2021-04-21 23:47:28
@ControlAltDel:感谢您主动删除不再是最佳答案的答案。希望其他人也有类似的纪律
2021-04-28 23:47:28
说明答案的几行代码比仅指向 API 的链接更可取。不要不同意答案,只是不要相信它足够完整。
2021-05-03 23:47:28
@DanDascalescu 我同意你的看法。问题是我 7 年前写了这个答案,我没有跟上 node.js 。如果你是其他人想更新它,那就太好了。或者我可以简单地删除它,因为似乎已经有了更好的答案。你会推荐什么?
2021-05-08 23:47:28

你怎么看待这件事 ?

async function streamToString(stream) {
    // lets have a ReadableStream as a stream variable
    const chunks = [];

    for await (const chunk of stream) {
        chunks.push(Buffer.from(chunk));
    }

    return Buffer.concat(chunks).toString("utf-8");
}

@DirkSchumacher 不打扰。看看您是否能准确地找出 IDE 的哪个组件——我假设它是一个程序——加载并执行包含for await. 查询程序的版本,看看版本是否真的支持语法。然后找出您的 IDE 使用该程序的特定“过时”版本的原因,并找到一种方法来更新两者。
2021-04-17 23:47:28
@DirkSchumacher 您的 IDE 要么使用过时的脚本解释器(for await是有效的 ECMAScript 语法),要么在尝试(不成功)执行某些包含for await. 是哪个IDE?无论如何,IDE 并不是为了在“生产中”实际运行程序而设计的,它们会在开发过程中对它们进行整理并帮助进行分析。
2021-04-18 23:47:28
哇,这看起来很整洁!这是否有任何问题(除了上述评论中提到的问题)?它可以处理错误吗?
2021-04-20 23:47:28
不得不使用chunks.push(Buffer.from(chunk));它来处理字符串块。
2021-04-22 23:47:28
这是现代版的最佳答案。哇 Node.js/JS 变化很快。我建议使用这个而不是最受好评的一个,因为它更干净并且不会让用户不得不触摸事件。
2021-04-27 23:47:28