如何将节点js变换流用作读取流?

时间:2018-05-25 23:37:19

标签: javascript node.js amazon-s3 stream aws-sdk

我正在尝试使用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

总之,我不确定我的实现有什么问题,如果使用流是完成我正在尝试执行的任务的可行方法。

1 个答案:

答案 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 });
    });
});