如何从一个可写流(Writable stream)创建一个可读流(Readable stream)?(Node.js)

17

我正在使用Exceljs动态地创建Excel数据。

我希望将其缓存在内存中,然后使用Koa将其发送给用户。

Exceljs的write方法需要一个可写流:

workbook.xlsx.write(writableStream, options)

但是Koa需要一个可读流:

response.body = readableStream

我知道我可以将可读流传输到可写流中,但是如何做相反的操作呢?我希望Exceljs将数据写入可写流,并让Koa从同一流中读取。我对流API感到非常沮丧!

除了其他20件事情外,我尝试了这个:

const ReadableStream = require("memory-streams").ReadableStream

const reader = new ReadableStream()

const writer = new stream.Writable({
    write: function(chunk, encoding, next) {
        console.log(chunk.toString())
        // reader.push(chunk, encoding)
        next()
    }
})

const reader = new MemoryStream(null, {readable: true})
// reader.write = reader.unshift
const writer = reader

workbook.xlsx.write(writer, {})
return reader

但是它不起作用,我遇到了一些奇怪的错误,说无法写入已关闭的流。即使我处理了这个错误,我的Excel文件也不会打开。

那么我该如何将可写流转换为可读流呢?

3个回答

13

你是否考虑过使用Passthrough流?它是一个简单的变换流,可以传递所有传递给它的数据,因此您可以从可写流中读取。


如果您只想获取一个流、修改该流并将其流式传输到其他地方,这是一个很好的选择。 - Developerium

13

你需要一个转换流,它既可读又可写。

stream = new require('stream').Transform()
stream._transform = function (chunk,encoding,done) 
{
    this.push(chunk)
    done()
}

3
我看了文档后感到头昏眼花。有什么建议吗?我在寻找像恒等函数一样的简单转换,即不做任何事情的转换。 - Max Heiber
2
有几件事情需要理解才能明白发生了什么......你如何使用这个 Transform?你如何将它连接到可写/可读流中(这是最初的问题)? - Felipe Sabino

9

对于所有需要可读写流的人,这是最终适用于我的方法。

使用案例是QRCode包从动态变量(例如:userId)生成QRCode png图像,仅使用stream.Writable --> 上传到AWS S3存储桶仅使用stream.Readable。

import QRCode from 'qrcode';
import AWS from 'aws-sdk';
import { Transform } from 'stream';

const userId = 'userIdString';

// AWS Config, import this from a safe place!!!
AWS.config.update({
  accessKeyId: 'xxxxxxxxxx',
  secretAccessKey: 'xxxxxxxxx',
  region: 'xxxxxxx',
});

const s3 = new AWS.S3({ apiVersion: '2006-03-01' });

// Create Stream, Writable AND Readable
const inoutStream = new Transform({
  transform(chunk, encoding, callback) {
    this.push(chunk);
    callback();
  },
});

// Need writable stream
QRCode.toFileStream(inoutStream, userId);

//Just to check
inoutStream.on('finish', () => {
  console.log('finished writing');
});

// Need readable stream
  s3.upload(
    {
      Bucket: 'myBucket',
      Key: `QR_${userId}.png`,
      Body: inoutStream,
      // ACL: 'public-read',
      ContentType: 'image/png',
    },
    (err, data) => {
      console.log(err, data);
    },
  )
  .on('httpUploadProgress', (evt) => {
    console.log(evt);
  })
  .send((err, data) => {
    console.log(err, data);
  });

如果你之前从未使用过流(stream),这是一个非常好的资源。


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