Как записать файл или данные в объект S3 с помощью boto3

Ответы:

219

В Boto 3 методы Key.set_contents_from_ были заменены на

Например:

import boto3

some_binary_data = b'Here we have some data'
more_binary_data = b'Here we have some more data'

# Method 1: Object.put()
s3 = boto3.resource('s3')
object = s3.Object('my_bucket_name', 'my/key/including/filename.txt')
object.put(Body=some_binary_data)

# Method 2: Client.put_object()
client = boto3.client('s3')
client.put_object(Body=more_binary_data, Bucket='my_bucket_name', Key='my/key/including/anotherfilename.txt')

В качестве альтернативы двоичные данные могут быть получены при чтении файла, как описано в официальных документах, сравнивающих boto 2 и boto 3 :

Хранение данных

Хранить данные из файла, потока или строки очень просто:

# Boto 2.x
from boto.s3.key import Key
key = Key('hello.txt')
key.set_contents_from_file('/tmp/hello.txt')

# Boto 3
s3.Object('mybucket', 'hello.txt').put(Body=open('/tmp/hello.txt', 'rb'))
jkdev
источник
botocore.exceptions.NoCredentialsError: Не удается найти учетные данные, как это исправить?
Дипак Мурти
2
@deepakmurthy Я не уверен, почему вы получаете эту ошибку ... Вам нужно задать новый вопрос о переполнении стека и предоставить более подробную информацию о проблеме.
jkdev
1
Когда я пытаюсь, s3.Object().put()я получаю объект с нулем content-length. Для меня put()принимает только строковые данные, но, put(str(binarydata)) похоже, есть какие-то проблемы с кодировкой. Я получаю объект, размер которого примерно в 3 раза превышает размер исходных данных, что делает его бесполезным для меня.
user1129682
@ user1129682 Я не уверен, почему это так. Не могли бы вы задать новый вопрос и предоставить более подробную информацию?
jkdev
@jkdev Было бы здорово, если бы вы могли посмотреть .
user1129682
51

В boto3 также есть метод прямой загрузки файла:

s3.Bucket('bucketname').upload_file('/local/file/here.txt','folder/sub/path/to/s3key')

http://boto3.readthedocs.io/en/latest/reference/services/s3.html#S3.Bucket.upload_file

EM Bee
источник
5
Это хорошо, но не позволяет хранить данные в памяти.
Reid
3
@Reid: для файлов в памяти вы можете использовать s3.Bucket(...).upload_fileobj()вместо этого метод.
svohara
40

Вам больше не нужно преобразовывать содержимое в двоичное перед записью в файл в S3. В следующем примере создается новый текстовый файл (с именем newfile.txt) в корзине S3 со строковым содержимым:

import boto3

s3 = boto3.resource(
    's3',
    region_name='us-east-1',
    aws_access_key_id=KEY_ID,
    aws_secret_access_key=ACCESS_KEY
)
content="String content to write to a new S3 file"
s3.Object('my-bucket-name', 'newfile.txt').put(Body=content)
Franke
источник
Понятия не имею, что у моего действия "положить" нет доступа. Я создал это ведро и поместил свой канонический идентификатор в список доступа.
Chen Lin
Как prefixв этом случае поставить оценку? То есть, что если вы хотите сохранить файл my-bucket-name/subfolder/?
kev
3
@kev вы можете указать это вместе с именем файла 'subfolder / newfile.txt' вместо 'newfile.txt'
Мадхава Каррильо
Re: «Вам больше не нужно преобразовывать содержимое в двоичное перед записью в файл в S3.», Это где-то задокументировано? Я смотрел на boto3.amazonaws.com/v1/documentation/api/latest/reference/… и думал, что он принимает только байты. Я не уверен, что именно представляет собой «доступный для поиска файловый объект», но не думал, что это включает строки.
Эмма
Возможно, я сравнивал это с download_fileobj (), который предназначен для загрузки больших файлов из нескольких частей. Методы загрузки требуют файловых объектов , доступных для поиска , но put () позволяет записывать строки непосредственно в файл в корзине, что удобно для лямбда-функций для динамического создания и записи файлов в корзину S3.
Franke
28

Вот хороший трюк для чтения JSON из s3:

import json, boto3
s3 = boto3.resource("s3").Bucket("bucket")
json.load_s3 = lambda f: json.load(s3.Object(key=f).get()["Body"])
json.dump_s3 = lambda obj, f: s3.Object(key=f).put(Body=json.dumps(obj))

Теперь вы можете использовать json.load_s3и json.dump_s3с тем же API, что loadи иdump

data = {"test":0}
json.dump_s3(data, "key") # saves json to s3://bucket/key
data = json.load_s3("key") # read json from s3://bucket/key
Ури Горен
источник
2
Превосходно. Для того, чтобы получить его на работу, я добавил этот дополнительный бит: ...["Body"].read().decode('utf-8').
sedeh
Отличная идея. В любом случае, это дает некоторое пространство для обозначения улучшений.
Ян Влчинский,
Предлагаем переписать эту прекрасную идею: gist.github.com/vlcinsky/bbeda4321208aa98745afc29b58e90ac
Ян Влцинский,
15

Более чистая и лаконичная версия, которую я использую для загрузки файлов на лету в заданную корзину и подпапку S3.

import boto3

BUCKET_NAME = 'sample_bucket_name'
PREFIX = 'sub-folder/'

s3 = boto3.resource('s3')

# Creating an empty file called "_DONE" and putting it in the S3 bucket
s3.Object(BUCKET_NAME, PREFIX + '_DONE').put(Body="")

Примечание . Вы должны ВСЕГДА помещать свои учетные данные AWS ( aws_access_key_idи aws_secret_access_key) в отдельный файл, например:~/.aws/credentials

кев
источник
Каково эквивалентное расположение Windows для файла учетных данных AWS, поскольку Windows не поддерживает~
Хамман Самуэль,
1
@HammanSamuel, ты можешь хранить это какC:\Users\username\.aws\credentials
kev
2

Стоит упомянуть smart-open, который используется boto3в качестве back-end.

smart-openявляется заменой для питона , openкоторые могут открывать файлы s3, а также ftp, httpи многих других протоколов.

например

from smart_open import open
import json
with open("s3://your_bucket/your_key.json", 'r') as f:
    data = json.load(f)

Учетные данные aws загружаются через учетные данные boto3 , обычно это файл в каталоге ~/.aws/или переменная среды.

Ури Горен
источник
1
Хотя этот ответ является информативным, он не соответствует ответу на исходный вопрос, а именно, каковы эквиваленты boto3 определенных методов boto.
robinhood91
2
Smart open использует boto3
Ури Горен
1

Вы можете использовать приведенный ниже код для записи, например, образа для S3 в 2019 году. Чтобы иметь возможность подключиться к S3, вам необходимо установить AWS CLI с помощью команды pip install awscli, а затем ввести несколько учетных данных с помощью команды aws configure:

import urllib3
import uuid
from pathlib import Path
from io import BytesIO
from errors import custom_exceptions as cex

BUCKET_NAME = "xxx.yyy.zzz"
POSTERS_BASE_PATH = "assets/wallcontent"
CLOUDFRONT_BASE_URL = "https://xxx.cloudfront.net/"


class S3(object):
    def __init__(self):
        self.client = boto3.client('s3')
        self.bucket_name = BUCKET_NAME
        self.posters_base_path = POSTERS_BASE_PATH

    def __download_image(self, url):
        manager = urllib3.PoolManager()
        try:
            res = manager.request('GET', url)
        except Exception:
            print("Could not download the image from URL: ", url)
            raise cex.ImageDownloadFailed
        return BytesIO(res.data)  # any file-like object that implements read()

    def upload_image(self, url):
        try:
            image_file = self.__download_image(url)
        except cex.ImageDownloadFailed:
            raise cex.ImageUploadFailed

        extension = Path(url).suffix
        id = uuid.uuid1().hex + extension
        final_path = self.posters_base_path + "/" + id
        try:
            self.client.upload_fileobj(image_file,
                                       self.bucket_name,
                                       final_path
                                       )
        except Exception:
            print("Image Upload Error for URL: ", url)
            raise cex.ImageUploadFailed

        return CLOUDFRONT_BASE_URL + id
Пратик Бхувания
источник