繁体   English   中英

如何从 S3 存储桶中读取 CSV 文件,对其应用某些 if 语句,并编写新的更新的 CSV 文件并将其放入 S3 存储桶?

[英]How can I read from a CSV file from an S3 bucket, apply certain if-statements to it, and write a new updated CSV file and place it in the S3 bucket?

我在将新的 CSV 文件写入 S3 存储桶时遇到问题。 我希望能够读取 S3 存储桶中的 CSV 文件,如果 CSV 中的某个值符合特定要求,我想将其更改为其他值。 我读到无法编辑 S3 对象,因此我每次都需要创建一个新对象。 简而言之,我想从 S3 存储桶中的另一个 CSV 文件创建一个新的、更新的 CSV 文件,并应用更改。

我正在尝试使用 DictWriter 和 DictReader,但我总是遇到 DictWriter 的问题。 我可以正确读取 CSV 文件,但是当我尝试更新它时,与 DictWriter 存在大量明显不同的问题。 现在,我得到的问题是

# Function to be pasted into AWS Lambda.
# Accesses S3 bucket, opens the CSV file, receive the response line-by-line, 

# To be able to access S3 buckets and the objects within the bucket
import boto3

# To be able to read the CSV by using DictReader 
import csv

# Lambda script that extracts, transforms, and loads data from S3 bucket 'testing-bucket-1042' and CSV file 'Insurance.csv'

def lambda_handler(event, context):
    s3 = boto3.resource('s3')
    bucket = s3.Bucket('testing-bucket-1042')
    obj = bucket.Object(key = 'Insurance.csv')
    response = obj.get()
    lines = response['Body'].read().decode('utf-8').split()

    reader = csv.DictReader(lines) 

    with open("s3://testing-bucket-1042/Insurance.csv", newline = '') as csvfile:
            reader = csv.DictReader(csvfile)
            fieldnames = ['county', 'eq_site_limit'] 
            writer = csv.DictWriter(lines, fieldnames=fieldnames)

            for row in reader: 
                writer.writeheader()
                if row['county'] == "CLAY": # if the row is under the column 'county', and contains the string "CLAY"
                    writer.writerow({'county': 'CHANGED'})
                if row['eq_site_limit'] == "0": # if the row is under the column 'eq_site_limit', and contains the string "0"
                    writer.writerow({'eq_site_limit': '9000'})

现在,我得到的错误是我在尝试打开 CSV 时使用的路径“s3://testing-bucket-1042/Insurance.csv”据说不存在。

错误说

"errorMessage": "[Errno 2] 没有这样的文件或目录:'s3://testing-bucket-1042/Insurance.csv'", "errorType": "FileNotFoundError"

如果有的话,使用 DictWriter 的正确方法是什么?

首先s3:\\\\不是通用(文件)协议,因此您会收到错误消息。 很好,你表达了你的意图。

好的,我重构了你的代码

import codecs

import boto3

# To be able to read the CSV by using DictReader
import csv
from io import StringIO

# Lambda script that extracts, transforms, and loads data from S3 bucket 'testing-bucket-1042' and CSV file 'Insurance.csv'

def lambda_handler(event, context):
    s3 = boto3.resource('s3')
    bucket = s3.Bucket('testing-bucket-1042')
    obj = bucket.Object(key = 'Insurance.csv')
    stream = codecs.getreader('utf-8')(obj.get()['Body'])
    lines = list(csv.DictReader(stream))
    ### now you have your object there

    csv_buffer = StringIO()
    out = csv.DictWriter(csv_buffer, fieldnames=['county', 'eq_site_limit'])

    for row in lines:
        if row['county'] == "CLAY":  
            out.writerow({'county': 'CHANGED'})
        if row['eq_site_limit'] == "0": 
            out.writerow({'eq_site_limit': '9000'})

    ### now write content into some different bucket/key

    s3client = boto3.client('s3')
    s3client.put_object(Body=csv_buffer.getvalue().encode(encoding),
                        Bucket=...targetbucket, Key=...targetkey)

我希望这有效。 基本上有几个技巧:

  • 使用codecs直接从 s3 存储桶流式传输 csv 数据
  • 使用BytesIO在内存中创建一个csv.DictWriter可以写入的流。
  • 完成后,“上传”内容的put_object方法是通过s3.clientsput_object方法(如 AWS 中所述)

为了在逻辑上将 AWS 代码与业务逻辑分开,我通常推荐这种方法:

  • 将对象从 Amazon S3下载/tmp目录
  • 执行所需的业务逻辑(读取文件、写入文件)
  • 将生成的文件上传到 Amazon S3

使用download_file()upload_file()可以避免担心内存中的流。 这意味着您可以采用通常对文件(例如在您自己的计算机上)进行操作的逻辑,然后将它们应用于从 S3 获得的文件。

这归结为个人喜好。

您可以使用 S3 的流式传输功能即时进行更改。 它更适合awksed等文本操作工具。

例子:

aws s3 cp s3://bucketname/file.csv - | sed 's/foo/bar/g' | aws s3 cp -  s3://bucketname/new-file.csv

AWS 文档: https : //docs.aws.amazon.com/cli/latest/reference/s3/cp.html

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM