使用节点fs从aws s3存储桶读取文件

Joe*_*oel 63 amazon-s3 fs amazon-web-services node.js

我试图读取aws s3存储桶中的文件

fs.readFile(file, function (err, contents) {
  var myLines = contents.Body.toString().split('\n')
})
Run Code Online (Sandbox Code Playgroud)

我已经能够使用节点aws-sdk下载和上传文件,但我不知道如何简单地阅读它并解析内容.

这是我如何从s3读取文件的示例:

var s3 = new AWS.S3();
var params = {Bucket: 'myBucket', Key: 'myKey.csv'}
var s3file = s3.getObject(params)
Run Code Online (Sandbox Code Playgroud)

dug*_*dug 77

你有几个选择.您可以将回调包含为第二个参数,将使用任何错误消息和对象调用该参数.此示例直接来自AWS文档:

s3.getObject(params, function(err, data) {
  if (err) console.log(err, err.stack); // an error occurred
  else     console.log(data);           // successful response
});
Run Code Online (Sandbox Code Playgroud)

或者,您可以将输出转换为流.AWS文档中还有一个示例:

var s3 = new AWS.S3({apiVersion: '2006-03-01'});
var params = {Bucket: 'myBucket', Key: 'myImageFile.jpg'};
var file = require('fs').createWriteStream('/path/to/file.jpg');
s3.getObject(params).createReadStream().pipe(file);
Run Code Online (Sandbox Code Playgroud)

  • @verveguy您可以使用以下命令:`new Promise((resolve,reject)=> {s3.getObject(params).createReadStream().on('end',()=> {return resolve();}). on('error',(error)=> {return reject(error);}).pipe(file)});` (12认同)
  • @verveguy 根据您运行的节点版本,aws-sdk 版本 > 2.3.0 将使用本机承诺。您还可以明确配置要使用的承诺库。`if (typeof Promise === 'undefined') { console.log("Using Bluebird for Promises"); AWS.config.setPromisesDependency(require('bluebird')); }` (2认同)

Lai*_*Xue 33

这样做:

new AWS.S3().getObject({ Bucket: this.awsBucketName, Key: keyName }, function(err, data)
{
    if (!err)
        console.log(data.Body.toString());
});
Run Code Online (Sandbox Code Playgroud)


Jas*_*son 22

因为您似乎想要逐行处理S3文本文件.这是一个使用标准readline模块和AWS'createReadStream()的Node版本

const readline = require('readline');

const rl = readline.createInterface({
    input: s3.getObject(params).createReadStream()
});

rl.on('line', function(line) {
    console.log(line);
})
.on('close', function() {
});
Run Code Online (Sandbox Code Playgroud)

  • 如果要处理压缩的源文件,则可以将s3.getObject(params).createReadStream()。pipe(zlib.createGunzip())用作InputStream。 (3认同)

rya*_*ndb 17

如果您想避免回调,您可以利用 sdk .promise() 函数,如下所示:

const s3 = new AWS.S3();
const params = {Bucket: 'myBucket', Key: 'myKey.csv'}
const response = await s3.getObject(params).promise() // await the promise
const fileContent = response.Body.toString('utf-8'); // can also do 'base64' here if desired
Run Code Online (Sandbox Code Playgroud)

我确信这里提到的其他方法都有其优点,但这对我来说非常有用。源自此线程(请参阅 AWS 的最后响应):https://forums.aws.amazon.com/thread.jspa ?threadID=116788


Gus*_*ube 8

我无法理解为什么,但createReadStream/ pipe方法对我不起作用.我试图下载一个大的CSV文件(300MB +),我得到了重复的行.这似乎是一个随机的问题.每次尝试下载时,最终文件大小都不同.

我最终使用另一种方式,基于AWS JS SDK示例:

var s3 = new AWS.S3();
var params = {Bucket: 'myBucket', Key: 'myImageFile.jpg'};
var file = require('fs').createWriteStream('/path/to/file.jpg');

s3.getObject(params).
    on('httpData', function(chunk) { file.write(chunk); }).
    on('httpDone', function() { file.end(); }).
    send();
Run Code Online (Sandbox Code Playgroud)

这样,它就像一个魅力.


Cos*_*tin 6

我更喜欢Buffer.from(data.Body).toString('utf8')。它支持编码参数。对于其他 AWS 服务(例如 Kinesis Streams),有人可能希望将'utf8'编码替换为'base64'.

new AWS.S3().getObject(
  { Bucket: this.awsBucketName, Key: keyName }, 
  function(err, data) {
    if (!err) {
      const body = Buffer.from(data.Body).toString('utf8');
      console.log(body);
    }
  }
);
Run Code Online (Sandbox Code Playgroud)


小智 5

这是我用来从s3检索和解析json数据的示例。

    var params = {Bucket: BUCKET_NAME, Key: KEY_NAME};
    new AWS.S3().getObject(params, function(err, json_data)
    {
      if (!err) {
        var json = JSON.parse(new Buffer(json_data.Body).toString("utf8"));

       // PROCESS JSON DATA
           ......
     }
   });
Run Code Online (Sandbox Code Playgroud)


lor*_*isi 5

从 S3 非常大的文件下载时,我遇到了完全相同的问题。

AWS 文档中的示例解决方案不起作用:

var file = fs.createWriteStream(options.filePath);
        file.on('close', function(){
            if(self.logger) self.logger.info("S3Dataset file download saved to %s", options.filePath );
            return callback(null,done);
        });
        s3.getObject({ Key:  documentKey }).createReadStream().on('error', function(err) {
            if(self.logger) self.logger.error("S3Dataset download error key:%s error:%@", options.fileName, error);
            return callback(error);
        }).pipe(file);
Run Code Online (Sandbox Code Playgroud)

虽然此解决方案有效:

    var file = fs.createWriteStream(options.filePath);
    s3.getObject({ Bucket: this._options.s3.Bucket, Key: documentKey })
    .on('error', function(err) {
        if(self.logger) self.logger.error("S3Dataset download error key:%s error:%@", options.fileName, error);
        return callback(error);
    })
    .on('httpData', function(chunk) { file.write(chunk); })
    .on('httpDone', function() { 
        file.end(); 
        if(self.logger) self.logger.info("S3Dataset file download saved to %s", options.filePath );
        return callback(null,done);
    })
    .send();
Run Code Online (Sandbox Code Playgroud)

由于某种原因,该createReadStream尝试不会触发end,closeerror回调。请参阅此处

我还使用该解决方案将档案记录到 gzip,因为第一个(AWS 示例)在这种情况下也不起作用:

        var gunzip = zlib.createGunzip();
        var file = fs.createWriteStream( options.filePath );

        s3.getObject({ Bucket: this._options.s3.Bucket, Key: documentKey })
        .on('error', function (error) {
            if(self.logger) self.logger.error("%@",error);
            return callback(error);
        })
        .on('httpData', function (chunk) {
            file.write(chunk);
        })
        .on('httpDone', function () {

            file.end();

            if(self.logger) self.logger.info("downloadArchive downloaded %s", options.filePath);

            fs.createReadStream( options.filePath )
            .on('error', (error) => {
                return callback(error);
            })
            .on('end', () => {
                if(self.logger) self.logger.info("downloadArchive unarchived %s", options.fileDest);
                return callback(null, options.fileDest);
            })
            .pipe(gunzip)
            .pipe(fs.createWriteStream(options.fileDest))
        })
        .send();
Run Code Online (Sandbox Code Playgroud)


kga*_*har 5

如果你想节省内存并希望将每一行作为json对象获取,那么你可以使用fast-csv创建readstream并可以将每一行作为json对象读取,如下所示:

const csv = require('fast-csv');
const AWS = require('aws-sdk');

const credentials = new AWS.Credentials("ACCESSKEY", "SECRETEKEY", "SESSIONTOKEN");
AWS.config.update({
    credentials: credentials, // credentials required for local execution
    region: 'your_region'
});
const dynamoS3Bucket = new AWS.S3();
const stream = dynamoS3Bucket.getObject({ Bucket: 'your_bucket', Key: 'example.csv' }).createReadStream();

var parser = csv.fromStream(stream, { headers: true }).on("data", function (data) {
    parser.pause();  //can pause reading using this at a particular row
    parser.resume(); // to continue reading
    console.log(data);
}).on("end", function () {
    console.log('process finished');
});
Run Code Online (Sandbox Code Playgroud)


Rip*_*nik 5

使用新版本的 sdk,接受的答案不起作用 - 它不会等待对象被下载。以下代码片段将有助于新版本:

// dependencies

const AWS = require('aws-sdk');

// get reference to S3 client

const s3 = new AWS.S3();

exports.handler = async (event, context, callback) => {

var bucket = "TestBucket"

var key = "TestKey"

   try {

      const params = {
            Bucket: Bucket,
            Key: Key
        };

       var theObject = await s3.getObject(params).promise();

    } catch (error) {
        console.log(error);
        return;
    }  
}
Run Code Online (Sandbox Code Playgroud)

  • var theObject = wait s3.getObject(params).promise() 这是正确的方法。谢谢 (3认同)