繁体   English   中英

如何使用节点 js 转换 stream 作为读取 stream?

[英]How to use node js transform stream as a read stream?

我正在尝试使用 node.js 中的 AWS-SDK 下载、就地修改并将文件重新上传到 Amazon S3。 我是 node 新手,经过一番谷歌搜索后,我选择尝试使用流实现此逻辑。 我通过stream.Transform并提供一个transform function 创建了一个自定义变换 stream。 我目前的实现是:

// Download and modify file.
var outputStream = s3.getObject(getParams).
    createReadStream().
    pipe(transformStream);

// Upload modified file by passing outputStream as body to s3.putObject.
// s3.putObjectWrapper is a promise wrapper for the api function putObject.
s3.putObjectWrapper({body: outputStream, ...}).
    then((data) => {
        logger.debug("Put Success: ", {data: data});
    }).
    catch((err) => {
        logger.error("Put Error: ", {error: err});
    });

这会产生以下错误 output:

error: Put Error: message=Cannot determine length of [object Object], objectMode=false, highWaterMark=16384, head=null, tail=null, length=0, length=0, pipes=null, pipesCount=0, flowing=null, ended=false, endEmitted=false, reading=false, sync=false, needReadable=true, emittedReadable=false, readableListening=false, resumeScheduled=false, defaultEncoding=utf8, ranOut=false, awaitDrain=0, readingMore=false, decoder=null, encoding=null, readable=true, domain=null, end=function

我已在此处阅读有关流的节点文档(请参阅下面的链接)。 I did not find them helpful and I am unsure if I also have to implement stream.Read methods in my custom transform stream class, of which transformStream is an instance, to support readability of the stream. 另请注意,function s3.putObject 接受缓冲区 stream 或字符串作为其主体。 因此,如果我可以使用缓冲区而不是将 stream 传递给putObject来实现相同的功能,那将很有用。 node.js 流: https://nodejs.org/dist/latest-v10.x/docs/api/stream.html aws-sdk S3 api: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property

总之,我不确定我的实现有什么问题,以及使用流是否是完成我要执行的任务的可行方法。

s3.putObject存在一个问题 ,该问题仅支持使用fs.creatReadStream创建的流,但是您可以fs.creatReadStream设置流的长度来解决此问题。 问题在于,如果您不知道流的长度,则需要事先知道它的长度,这很可能是因为您要对其进行转换,因此需要将其通过管道传输到文件中,然后传递可读的使用fs.createReadStream流。 或者更好的是,使用s3.upload代替,这将允许您使用任何可读流。

使用s3.upload

const params = { Bucket: 'bucket', Key: 'Filename', Body: stream };
s3.upload(params, (err, data) => {
  console.log(err, data);
});

使用s3.putObject

// This will work if you know the length beforehand
outputStream.length = getStreamLength(); 

s3.putObjectWrapper({ body: outputStream })

以下将起作用。 即使可能不是任何人在使用流时所期望的。

const writeStream = fs.createWriteStream('/tmp/testing');

var outputStream = s3.getObject(getParams)
    .createReadStream().
    .pipe(transformStream)
    .pipe(writeStream)


 writeStream.on('close', () => {

    const readStream = fs.createReadStream('/tmp/testing');

    s3.putObjectWrapper({
      body: readStream
    })
    .then(data => {
      logger.debug("Put Success: ", { data: data });
    })
    .catch(err => {
      logger.error("Put Error: ", { error: err });
    });
});

实际上,您可以在为PutObjectCommand命令指定ContentLength属性时使用Transform

import { createReadStream } from 'node:fs'
import { stat } from 'node:fs/promises'
import { S3, PutObjectCommand } from '@aws-sdk/client-s3'

const read = createReadStream(src, {})
const { size } = await stat(src)

// create your transform stream
const transform = new Transform({
  transform(chunk, encoding, callback) {
    try {
      // read / update stream as you needs
      this.push(chunk)
      callback()
    } catch (error) {
      callback(error)
    }
  }
})

// get the new stream
const transformed = read.pipe(transform)

// upload transformed stream to s3
const s3 = new S3({ /* ... */ })
s3.send(
  new PutObjectCommand({
    Bucket: config.digitalOcean.releasesBucket,
    Key: key,
    Body: transformed,

    // the ContentLength is required here when using transform
    ContentLength: size,
  })
)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM