[英]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.