在Node.js中将缓冲区转换为可读流

166

我有一个库,它以ReadableStream作为输入参数,但我的输入只是一张base64格式的图片。我可以这样将我的数据转换成一个Buffer

var img = new Buffer(img_string, 'base64');

但我不知道如何将其转换为ReadableStream,或者将我获得的Buffer转换为ReadableStream

有什么办法可以做到这一点吗?

9个回答

230

对于Node.js 10.17.0及以上版本:

const { Readable } = require('stream');

const stream = Readable.from(myBuffer);

2
这对图像文件有任何影响吗? - HexaCrop
4
它可以解决 OP 描述的情况,但如果缓冲区包含二进制数据,使用 .toString() 将会破坏它。 - Ihor Sakailiuk

98

类似这样的内容...

import { Readable } from 'stream'

const buffer = new Buffer(img_string, 'base64')
const readable = new Readable()
readable._read = () => {} // _read is required but you can noop it
readable.push(buffer)
readable.push(null)

readable.pipe(consumer) // consume the stream
在一般情况下,可读流的 _read 函数应该从底层源收集数据并逐步使用 push 方法将其推送,以确保在需要之前不会将大量源代码收集到内存中。
但在这种情况下,您已经将源代码保存在内存中,因此不需要使用 _read
推送整个缓冲区只是将其包装在可读流 API 中。

2
_read() 方法内部 push() 缓冲区是否更正确呢?即 readable._read = () => {readable.push(buffer); readable.push(null);}。不确定这是否重要,但允许流管理何时提供数据似乎不太可能遇到意外行为。除此之外,这应该是被接受的答案,因为它不依赖于第三方模块。 - broofa
1
一般来说,你是对的,但对于这个特定的用例,我不会在read方法内部使用push。从概念上讲,我认为_read应该保留用于从底层源中“收集”数据。在这种情况下,我们不仅在内存中拥有数据,而且不需要进行转换。因此,对于将数据包装在流中,这就是我会这样做的方式,但是对于在流中转换或累积数据,该逻辑将发生在_read方法中。 - Mr5o1
你的底层源代码是缓冲区 ;) - Franck Freiburger
@FranckFreiburger 是的,但你并不是从那个源“收集”数据,它已经在内存中了,而且你总是会一口气全部消耗掉它,你不会按需拉取它。 - Mr5o1

36

31

您可以使用Node Stream Buffers创建一个可读流,方法如下:


// Initialize stream
var myReadableStreamBuffer = new streamBuffers.ReadableStreamBuffer({
  frequency: 10,      // in milliseconds.
  chunkSize: 2048     // in bytes.
}); 

// With a buffer
myReadableStreamBuffer.put(aBuffer);

// Or with a string
myReadableStreamBuffer.put("A String", "utf8");

频率不能为0,因此这将引入一定的延迟。


谢谢,虽然有点晚了。我不记得我是怎么解决这个问题的,但这看起来是一个不错的解决方案。如果有人确认一下就太好了。我记得当时找到的关于这种转换的资料为零。 - Masiar
1
确认它可行 - 当查找如何将文件缓冲区转换为流时发现了这个。 - Jack Lawson
2
毫秒不是频率的度量单位 - 我想他们指的是周期。 - UpTheCreek
@UpTheCreek 我无法更改它,因为这是属性名称,单位就是毫秒。 - vanthome
@vanthome - 我并不是在暗示这是你的错 :) 只是 node-stream-buffer 开发者命名不够规范。 - UpTheCreek
显示剩余2条评论

22

您可以使用标准的NodeJS流API进行操作 - stream.Readable.from

const { Readable } = require('stream');
const stream = Readable.from(buffer);
注意:如果缓冲区包含二进制数据,请勿将其转换为字符串(使用buffer.toString())。这会导致二进制文件损坏。

我注意到这仅适用于Node.js 12+。在我的测试中,“readable.push(buffer)”方法可与Node.js 8.17.0和Node.js 10.24.1一起使用。由于我坚持使用受支持的Node.js版本,因此这对我来说不是问题。 - Robert G. Schaffrath
它很干净,而且对我也很有效。 - 吳約南

10

您不需要为单个文件添加整个npm库。我将其重构为TypeScript:

import { Readable, ReadableOptions } from "stream";

export class MultiStream extends Readable {
  _object: any;
  constructor(object: any, options: ReadableOptions) {
    super(object instanceof Buffer || typeof object === "string" ? options : { objectMode: true });
    this._object = object;
  }
  _read = () => {
    this.push(this._object);
    this._object = null;
  };
}

基于node-streamifier(如上所述,是最佳选择)。


7

这是我对此的简单代码。

import { Readable } from 'stream';

const newStream = new Readable({
                    read() {
                      this.push(someBuffer);
                    },
                  })

7
这里有一个简单的解决方案,使用 streamifier 模块。
const streamifier = require('streamifier');
streamifier.createReadStream(new Buffer ([97, 98, 99])).pipe(process.stdout);

您可以使用字符串、缓冲区和对象作为其参数。

1
另一个等效的选择是tostreamconst toStream = require('tostream'); toStream(new Buffer ([97, 98, 99])).pipe(process.stdout); - Yushin Washio
1
@YushinWashio 当然。Node中有很多模块可用。 - Shwetabh Shekhar

2

试试这个:

const Duplex = require('stream').Duplex;  // core NodeJS API
function bufferToStream(buffer) {  
  let stream = new Duplex();
  stream.push(buffer);
  stream.push(null);
  return stream;
}

来源: Brian Mancini -> http://derpturkey.com/buffer-to-stream-in-node/

这篇文章介绍了在Node.js中如何将Buffer转换为Stream。通过使用Node.js内置的Transform流,可以将Buffer对象有效地转换为可读流或可写流。此外,该文章还提供了一些实用代码示例,以帮助读者更好地理解如何使用这些流进行数据处理。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接