2015-03-31 20 views
83

Sto provando a fare un "ciao mondo" con il nuovo client boto3 per AWS.Come salvare l'oggetto S3 in un file utilizzando boto3

Il caso d'uso che ho è abbastanza semplice: ottenere l'oggetto da S3 e salvarlo nel file.

In boto 2.X vorrei fare in questo modo:

import boto 
key = boto.connect_s3().get_bucket('foo').get_key('foo') 
key.get_contents_to_filename('/tmp/foo') 

In boto 3. Non riesco a trovare un modo pulito per fare la stessa cosa, quindi sono manualmente l'iterazione sopra l'oggetto "Streaming":

import boto3 
key = boto3.resource('s3').Object('fooo', 'docker/my-image.tar.gz').get() 
with open('/tmp/my-image.tar.gz', 'w') as f: 
    chunk = key['Body'].read(1024*8) 
    while chunk: 
     f.write(chunk) 
     chunk = key['Body'].read(1024*8) 

o

import boto3 
key = boto3.resource('s3').Object('fooo', 'docker/my-image.tar.gz').get() 
with open('/tmp/my-image.tar.gz', 'w') as f: 
    for chunk in iter(lambda: key['Body'].read(4096), b''): 
     f.write(chunk) 

e funziona benissimo. Mi chiedevo se ci fosse una funzione "nativa" di boto3 che farà lo stesso compito?

risposta

139

C'è una personalizzazione introdotta recentemente in Boto3 che aiuta (tra le altre cose) con questo. Attualmente è esposta al basso livello di client S3, e può essere utilizzato in questo modo:

s3_client = boto3.client('s3') 
open('hello.txt').write('Hello, world!') 

# Upload the file to S3 
s3_client.upload_file('hello.txt', 'MyBucket', 'hello-remote.txt') 

# Download the file from S3 
s3_client.download_file('MyBucket', 'hello-remote.txt', 'hello2.txt') 
print(open('hello2.txt').read()) 

Queste funzioni si occuperà automaticamente di lettura/scrittura di file così come fare uploads più parti in parallelo per file di grandi dimensioni.

+1

@ Daniel: Grazie per la risposta. Puoi rispondere alla domanda se voglio caricare il file utilizzando il caricamento multipart in boto3. –

+1

@RahulKumarPatle il metodo 'upload_file' utilizzerà automaticamente caricamenti multipart per file di grandi dimensioni. – Daniel

+0

@Daniel - Riguardo a multipart_upload, ho creato una [domanda SO] (http://stackoverflow.com/questions/34303775/complete-a-multipart-upload-with-boto3). Il metodo 'upload_file' non sembra utilizzare automaticamente il caricamento multipart per dimensioni di file che superano la configurazione' multipart_threshold'; almeno, non sono stato in grado di farlo funzionare in quel modo. Mi piacerebbe essere sbagliato! Qualsiasi aiuto è molto apprezzato. – blehman

43

boto3 ora ha un'interfaccia più gradevole rispetto al client:

resource = boto3.resource('s3') 
my_bucket = resource.Bucket('MyBucket') 
my_bucket.download_file(key, local_filename) 

Questo di per sé non è tremendamente meglio del client nella risposta accettato (anche se i documenti dicono che lo fa una migliore arrivi lavoro a riprovare e download in caso di errore) ma considerando che le risorse sono in genere più ergonomiche (ad esempio, le risorse s3 bucket e object sono più piacevoli rispetto ai metodi client) ciò consente di rimanere al livello risorse senza dover scendere.

Resources in genere possono essere creati allo stesso modo dei client e accettano tutti o quasi gli stessi argomenti e li inoltrano semplicemente ai client interni.

+1

Lo sto usando senza intoppi. Grazie. – arsho

+1

Grande esempio, e per aggiungere in quanto la domanda originale chiede di salvare un oggetto, il metodo rilevante qui è 'my_bucket.upload_file()' (o 'my_bucket.upload_fileobj()' se si dispone di un oggetto BytesIO). – SMX

31

Per quelli di voi che vogliono simulare il set_contents_from_string come i metodi boto2, si può provare

import boto3 
from cStringIO import StringIO 

s3c = boto3.client('s3') 
contents = 'My string to save to S3 object' 
target_bucket = 'hello-world.by.vor' 
target_file = 'data/hello.txt' 
fake_handle = StringIO(contents) 

# notice if you do fake_handle.read() it reads like a file handle 
s3c.put_object(Bucket=target_bucket, Key=target_file, Body=fake_handle.read()) 
+12

Questa è la risposta. Ecco la domanda: "Come si salva una stringa su un oggetto S3 usando boto3?" – jkdev

+0

per python3 Ho dovuto usare import io; fake_handl e = io.StringIO (contenuto) – Felix

5
# Preface: File is json with contents: {'name': 'Android', 'status': 'ERROR'} 

import boto3 
import io 

s3 = boto3.resource(
    's3', 
    aws_access_key_id='my_access_id', 
    aws_secret_access_key='my_secret_key' 
) 

obj = s3.Object('my-bucket', 'key-to-file.json') 
data = io.BytesIO() 
obj.download_fileobj(data) 

# object is now a bytes string, Converting it to a dict: 
new_dict = json.loads(data.getvalue().decode("utf-8")) 

print(new_dict['status']) 
# Should print "Error" 
+8

Non inserire mai AWS_ACCESS_KEY_ID o AWS_SECRET_ACCESS_KEY nel codice. Questi dovrebbero essere definiti con il comando awscli 'aws configure' e saranno trovati automaticamente da' botocore'. –

+0

Punto valido. Dovrebbe averlo incluso davvero. – SixDays

Problemi correlati