код ниже
import boto3
import csv
import json
# set up S3 connection
s3 = boto3.resource('s3')
my_bucket = s3.Bucket('csvfolder3')
# bucket_name = 'csvfolder3'
def lambda_handler(event, context):
for file in my_bucket.objects.all():
print(file.key)
body = file.get()['Body'].read()
print(body)
with open(file.key, 'r') as csvfile: #####[ERROR] FileNotFoundError: [Errno 2] No such file or directory: 'data.csv'
data = [row for row in csv.DictReader(csvfile)]
json_data = json.dumps(data)
s3.Object(my_bucket, 'file.json').put(Body=json_data)
как вы ожидаете, что это сработает? вы перебираете my_bucket.objects.all()
- все объекты в корзине S3. Вы работаете в функции AWS Lambda. Обратите внимание, что ваша функция Lambda волшебным образом не имеет всех (или каких-либо) ваших объектов S3, которые уже загружены и доступны для использования в локальном каталоге или в папке /tmp в этом случае.
@rv.kvetch Существует только один файл csv размером 1 КБ.
Когда у тебя есть:
body = file.get()['Body'].read()
Это уже загрузка содержимого файла (или объекта) в память в рамках функции AWS Lambda.
NB: следите за потребляемой памятью (МБ). При необходимости увеличьте объем памяти для функции Lambda.
Кроме того, я предполагаю, основываясь на документах, что ['Body'].read()
возвращает объект bytes
.
Итак, если у вас есть bytes
, вы можете превратить его в строку с помощью:
bytes_data.decode()
Затем создайте файлоподобный объект, как и ожидает csv.DictReader
, обернув приведенное выше:
StringIO(...)
Полный пример:
from __future__ import annotations
import csv
import json
from io import StringIO
byte_content = b"""
id,name,age,height,weight
1,Alice,20,62,120.6
2,Freddie,21,74,190.6
3,Bob,17,68,120.0
""".strip()
# set encoding if known
encoding = 'utf-8'
# decode bytes -> str
content = byte_content.decode(encoding)
# create file-like object
file = StringIO(content)
data: list[dict] = [row for row in csv.DictReader(file, delimiter = ",")]
json_data: str = json.dumps(data, indent=2)
print(json_data)
Результат:
[
{
"id": "1",
"name": "Alice",
"age": "20",
"height": "62",
"weight": "120.6"
},
{
"id": "2",
"name": "Freddie",
"age": "21",
"height": "74",
"weight": "190.6"
},
{
"id": "3",
"name": "Bob",
"age": "17",
"height": "68",
"weight": "120.0"
}
]
если я хочу конвертировать напрямую без body = file.get()['Body'].read()
, что мне делать? Также я получаю сообщение об ошибке #####[ERROR] FileNotFoundError: [Errno 2] Нет такого файла или каталога: 'data.csv'
Насколько я понимаю, невозможно преобразовать csv напрямую в json. причина в том, что ваши данные в формате CSV, и вы хотите, чтобы они были в формате JSON. Существует два подхода: 1) прочитать файл из S3 в виде байтов и обернуть его в файлоподобный объект или (2) прочитать файл из S3 в виде байтов, сохранить в локальную папку /tmp
и передать фактический файловый объект с помощью open
. Я бы сказал, что из этих двух подходов первый является наиболее простым. В любом случае вам нужно будет использовать csv.DictReader
или что-то подобное для преобразования из CSV > dict
> JSON.
как упомянул @rv.kvetch, есть два способа конвертировать файл,
первый метод уже сделан им
добавление второго метода
import boto3
import csv
import json
import os
# set up S3 connection
s3 = boto3.client('s3')
def lambda_handler(event, context):
# get bucket name and file name from event
bucket_name = event['Records'][0]['s3']['bucket']['name']
file_name = event['Records'][0]['s3']['object']['key']
# download CSV file from S3
csv_file_path = f'/tmp/{file_name}'
s3.download_file(bucket_name, file_name, csv_file_path)
# convert CSV data to JSON format
with open(csv_file_path, 'r') as csvfile:
data = [row for row in csv.DictReader(csvfile)]
json_data = json.dumps(data)
# upload JSON data to S3
json_file_path = f'{os.path.splitext(file_name)[0]}.json'
s3.put_object(Body=json_data, Bucket=bucket_name, Key=json_file_path)
return {
'statusCode': 200,
'body': json.dumps('CSV to JSON conversion successful!')
}
open()
ищет файл на локальном жестком диске. Предположительно, вы хотели вместо этого открыть файл в ведре s3?