【问题标题】:Simplest lambda function to copy a file from one s3 bucket to another将文件从一个 s3 存储桶复制到另一个存储桶的最简单 lambda 函数
【发布时间】:2018-01-16 16:55:23
【问题描述】:

我完全不喜欢使用 AWS。我试图让一个非常简单和基本的操作工作。我想要做的是,在将文件上传到一个 s3 存储桶后,我希望该上传触发一个 Lambda 函数,该函数将该文件复制到另一个存储桶。

我进入 AWS 管理控制台,在 us-west2 服务器上创建了一个名为“test-bucket-3x1”的 s3 存储桶作为我的“源”存储桶,另一个名为“test-bucket-3x2”的存储桶作为我的“目的地'桶。创建这些存储桶时,我没有更改或修改任何设置。

在 Lambda 控制台中,我为“test-bucket-3x1”创建了一个 s3 触发器,将“事件类型”更改为“ObjectCreatedByPut”,并且没有更改任何其他设置。

这是我实际的 lamda_function 代码:

import boto3
import json
s3 = boto3.resource('s3')


def lambda_handler(event, context):
    bucket = s3.Bucket('test-bucket-3x1')
    dest_bucket = s3.Bucket('test-bucket-3x2')
    print(bucket)
    print(dest_bucket)

    for obj in bucket.objects():
        dest_key = obj.key
        print(dest_key)
        s3.Object(dest_bucket.name, dest_key).copy_from(CopySource = {'Bucket': obj.bucket_name, 'Key': obj.key})

当我使用 AWS Lambda 控制台提供的基本“HelloWorld”测试来测试这个函数时,我收到了这个”

{
  "errorMessage": "'s3.Bucket.objectsCollectionManager' object is not callable",
  "errorType": "TypeError",
  "stackTrace": [
    [
      "/var/task/lambda_function.py",
      12,
      "lambda_handler",
      "for obj in bucket.objects():"
    ]
  ]
}

我需要对我的代码进行哪些更改,以便在将文件上传到 test-bucket-3x1 时触发 lambda 函数并将文件复制到 test-bucket-3x2?

感谢您的宝贵时间。

【问题讨论】:

  • 您不应该使用for obj in bucket.objects.all() 而不是for obj in bucket.objects()。参考这个链接:boto3.readthedocs.io/en/latest/reference/services/…
  • "object is not callable" - 你正在尝试迭代它。我认为您可能希望使用 bucket.objects.all() 创建一个可迭代的
  • 感谢您的帮助。这似乎很愚蠢,但这对我来说真的很有用。我可以查看 cloudwatch 日志并开始了解 eventcontext 对象实际上是什么。在相关说明中,是否可以通过 lambda 打开/使用 s3 存储桶中的文件?例如,我可以将 csv 加载到 pandas 数据框中,操作数据框,返回操作后的数据框,然后将其上传到我的目标存储桶吗?会不会像在事件处理程序中放置 df = pd.read_excel(['Records']['bucket']['object']['key']) 之类的东西那么简单?
  • 请注意,如果您真正将所有新对象从一个存储桶复制到另一个存储桶,AWS 中有一个 S3 存储桶复制功能。

标签: python amazon-web-services amazon-s3 aws-lambda


【解决方案1】:

我将从蓝图开始s3-get-object 有关从蓝图创建 lambda 的更多信息,请使用this page

这是上面蓝图的代码:

console.log('Loading function');

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

const s3 = new aws.S3({ apiVersion: '2006-03-01' });


exports.handler = async (event, context) => {
    //console.log('Received event:', JSON.stringify(event, null, 2));

    // Get the object from the event and show its content type
    const bucket = event.Records[0].s3.bucket.name;
    const key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' '));
    const params = {
        Bucket: bucket,
        Key: key,
    };
    try {
        const { ContentType } = await s3.getObject(params).promise();
        console.log('CONTENT TYPE:', ContentType);
        return ContentType;
    } catch (err) {
        console.log(err);
        const message = `Error getting object ${key} from bucket ${bucket}. Make sure they exist and your bucket is in the same region as this function.`;
        console.log(message);
        throw new Error(message);
    }
};

然后您需要更新上面的代码,不仅可以获取对象信息,还可以复制和删除源,为此您可以参考以下答案:

const moveAndDeleteFile = async (file,inputfolder,targetfolder) => {
    const s3 = new AWS.S3();

    const copyparams = {
        Bucket : bucketname,
        CopySource : bucketname + "/" + inputfolder + "/" + file, 
        Key : targetfolder + "/" + file
    };

    await s3.copyObject(copyparams).promise();

    const deleteparams = {
        Bucket : bucketname,
        Key : inputfolder + "/" + file
    };

    await s3.deleteObject(deleteparams).promise();
    ....
}

来源:How to copy the object from s3 to s3 using node.js

【讨论】:

  • 谢谢,不幸的是这是node.js,OP要求python,这也是我所追求的......
【解决方案2】:
for object in source_bucket.objects.all():
    print(object)
    sourceObject = { 'Bucket' : 'bucketName', 'Key': object}
    destination_bucket.copy(sourceObject, object)

【讨论】:

  • 请不要只发布代码作为答案,还要解释您的代码的作用以及它如何解决问题的问题。这将使您的答案更有价值,更有可能吸引投票。
【解决方案3】:

您真的应该使用lambda_handler() 方法中的event 来获取文件[path|prefix|uri] 并只处理该文件,因为您的事件是在存储桶中的put 文件上触发的:

def lambda_handler(event, context):
    ...

    if event and event['Records']:
        for record in event['Records']:
            source_key = record['s3']['object']['key']

            ... # do something with the key: key-prefix/filename.ext

关于直接从 s3Bucket 打开文件的其他问题,我建议检查smart_open,“有点”像处理本地文件系统一样处理 s3Bucket:

from pandas import DataFrame, read_csv
from smart_open import open

def read_as_csv(file_uri: str): -> DataFrame
    with open(file_uri) as f:
       return read_csv(f, names=COLUMN_NAMES)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-04-14
    • 1970-01-01
    • 2018-11-22
    • 1970-01-01
    • 2023-02-01
    • 2013-11-01
    • 2020-07-05
    • 1970-01-01
    相关资源
    最近更新 更多