我正在尝试使用node.js中的AWS-SDK下载,修改并将文件重新上传到Amazon S3。我是节点新手,经过一些谷歌搜索后,我选择尝试使用流来实现这个逻辑。我通过继承stream.Transform
并提供transform
函数来创建自定义转换流。我目前的实施是:
// 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});
});
产生以下错误输出:
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
我在这里阅读了关于流的节点文档(参见下面的链接)。我没有发现它们有用,我不确定是否还必须在我的自定义转换流类中实现stream.Read方法,其中transformStream
是一个实例,以支持流的可读性。另请注意,函数s3.putObject接受缓冲区,流或字符串作为其主体。因此,如果我可以使用缓冲区实现相同的功能,而不是将流传递给putObject
,这将是有用的。
node.js streams: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
总之,我不确定我的实现有什么问题,如果使用流是完成我正在尝试执行的任务的可行方法。
答案 0 :(得分:0)
s3.putObject
有一个issue,它只支持使用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 });
});
});