Come scrivere un file o dati su un oggetto S3 utilizzando boto3


Risposte:


212

In boto 3, i metodi "Key.set_contents_from_" sono stati sostituiti da

Per esempio:

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')

In alternativa, i dati binari possono provenire dalla lettura di un file, come descritto nei documenti ufficiali che confrontano boto 2 e boto 3 :

Archiviazione dei dati

Archiviare i dati da un file, flusso o stringa è facile:

# 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'))

botocore.exceptions.NoCredentialsError: Impossibile individuare le credenziali come risolvere questo problema?
deepak murthy

2
@deepakmurthy Non sono sicuro del motivo per cui ricevi questo errore ... Dovresti porre una nuova domanda di Stack Overflow e fornire maggiori dettagli sul problema.
jkdev

1
Quando provo s3.Object().put()mi ritrovo con un oggetto con zero content-length. Per me put()accetta solo dati di stringa, ma put(str(binarydata)) sembra avere una sorta di problemi di codifica. Mi ritrovo con un oggetto circa 3 volte la dimensione dei dati originali, il che lo rende inutile per me.
user1129682

@ user1129682 Non sono sicuro del motivo. Potresti porre una nuova domanda e fornire maggiori dettagli?
jkdev

@jkdev Sarebbe fantastico se potessi dare un'occhiata .
user1129682


36

Non è più necessario convertire il contenuto in binario prima di scrivere nel file in S3. L'esempio seguente crea un nuovo file di testo (chiamato newfile.txt) in un bucket S3 con contenuto di stringa:

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)

Non ho idea che la mia azione "put" non abbia accesso. Ho creato questo bucket e ho inserito il mio ID canonico nell'elenco di accesso.
Chen Lin

Come si dà un prefixin questo caso? Significato, cosa succede se si desidera memorizzare il file in my-bucket-name/subfolder/?
kev

3
@kev puoi specificarlo insieme al nome del file 'sottocartella / nuovofile.txt' invece di 'nuovofile.txt'
Madhava Carrillo

Re "Non è più necessario convertire il contenuto in binario prima di scrivere nel file in S3.", È documentato da qualche parte? Stavo guardando boto3.amazonaws.com/v1/documentation/api/latest/reference/… e pensavo che accettasse solo byte. Non sono sicuro di cosa costituisca esattamente un "oggetto simile a un file ricercabile", ma non pensavo che includesse le stringhe.
Emma,

Potrei averlo confrontato con download_fileobj () che è per il caricamento di file multipart di grandi dimensioni. I metodi di caricamento richiedono oggetti file ricercabili , ma put () ti consente di scrivere stringhe direttamente in un file nel bucket, il che è utile per le funzioni lambda per creare e scrivere dinamicamente file in un bucket S3.
Franke

28

Ecco un bel trucco per leggere JSON da 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))

Ora puoi usare json.load_s3e json.dump_s3con la stessa API di loadedump

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
Eccellente. Per farlo funzionare, ho aggiunto questo qualcosa in più: ...["Body"].read().decode('utf-8').
sedeh

Grande idea. Ad ogni modo, fornisce un po 'di spazio per denominare i miglioramenti.
Jan Vlcinsky,

Proposta di riscrittura di questa bella idea: gist.github.com/vlcinsky/bbeda4321208aa98745afc29b58e90ac
Jan Vlcinsky

12

Una versione più pulita e concisa che utilizzo per caricare i file al volo in un determinato bucket S3 e sottocartella-

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="")

Nota : dovresti SEMPRE inserire le tue credenziali AWS ( aws_access_key_ide aws_secret_access_key) in un file separato, ad esempio-~/.aws/credentials


Qual è il percorso equivalente di Windows per il file delle credenziali AWS, dal momento che Windows non supporta~
Hamman Samuel

1
@HammanSamuel puoi memorizzarlo comeC:\Users\username\.aws\credentials
kev

1

vale la pena menzionare lo smart-open che utilizza boto3come back-end.

smart-openè un rimpiazzo per Python openin grado di aprire i file da s3, così come ftp, httpe molti altri protocolli.

per esempio

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

Le credenziali aws vengono caricate tramite le credenziali boto3 , di solito un file nella directory ~/.aws/o una variabile di ambiente.


1
sebbene questa risposta sia informativa, non aderisce alla risposta alla domanda originale, ovvero quali sono gli equivalenti boto3 di alcuni metodi boto.
robinhood91

1
Smart open utilizza boto3
Uri Goren

1

Puoi utilizzare il codice seguente per scrivere, ad esempio un'immagine su S3 nel 2019. Per poterti connettere a S3 dovrai installare AWS CLI utilizzando il comando pip install awscli, quindi inserire alcune credenziali utilizzando il comando 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.