example cli aws python amazon-web-services boto boto3

python - cli - Cómo guardar un objeto S3 en un archivo usando boto3



install boto3 (6)

Estoy tratando de hacer un "hola mundo" con el nuevo cliente boto3 para AWS.

El caso de uso que tengo es bastante simple: obtener un objeto de S3 y guardarlo en el archivo.

En boto 2.XI lo haría así:

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

En boto 3. No puedo encontrar una manera limpia de hacer lo mismo, así que estoy iterando manualmente sobre el objeto "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)

Y funciona bien. Me preguntaba si hay alguna función boto3 "nativa" que haga la misma tarea.


Cuando desee leer un archivo con una configuración diferente a la predeterminada, puede usar mpu.aws.s3_download(s3path, destination) directamente o el código copiado:

def s3_download(source, destination, exists_strategy=''raise'', profile_name=None): """ Copy a file from an S3 source to a local destination. Parameters ---------- source : str Path starting with s3://, e.g. ''s3://bucket-name/key/foo.bar'' destination : str exists_strategy : {''raise'', ''replace'', ''abort''} What is done when the destination already exists? profile_name : str, optional AWS profile Raises ------ botocore.exceptions.NoCredentialsError Botocore is not able to find your credentials. Either specify profile_name or add the environment variables AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN. See https://boto3.readthedocs.io/en/latest/guide/configuration.html """ exists_strategies = [''raise'', ''replace'', ''abort''] if exists_strategy not in exists_strategies: raise ValueError(''exists_strategy /'{}/' is not in {}'' .format(exists_strategy, exists_strategies)) session = boto3.Session(profile_name=profile_name) s3 = session.resource(''s3'') bucket_name, key = _s3_path_split(source) if os.path.isfile(destination): if exists_strategy is ''raise'': raise RuntimeError(''File /'{}/' already exists.'' .format(destination)) elif exists_strategy is ''abort'': return s3.Bucket(bucket_name).download_file(key, destination)


Hay una personalización que entró en Boto3 recientemente que ayuda con esto (entre otras cosas). Actualmente está expuesto en el cliente S3 de bajo nivel, y puede usarse así:

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

Estas funciones manejarán automáticamente la lectura / escritura de archivos, así como la carga de varias partes en paralelo para archivos grandes.


Para aquellos de ustedes que deseen simular set_contents_from_string como los métodos boto2, pueden intentar

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

Para Python3:

En python3, tanto StringIO como cStringIO se han ido . Use la importación StringIO como:

from io import StringIO

Para admitir ambas versiones:

try: from StringIO import StringIO except ImportError: from io import StringIO


boto3 ahora tiene una mejor interfaz que el cliente:

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

Esto en sí mismo no es tremendamente mejor que el client en la respuesta aceptada (aunque los documentos dicen que hace un mejor trabajo reintentando cargas y descargas en caso de error), pero teniendo en cuenta que los recursos son generalmente más ergonómicos (por ejemplo, el bucket y el object s3 los recursos son mejores que los métodos del cliente), esto le permite permanecer en la capa de recursos sin tener que desplegarse.

Resources generalmente se pueden crear de la misma manera que los clientes, y toman todos o la mayoría de los mismos argumentos y los envían a sus clientes internos.


Nota: Supongo que ha configurado la autenticación por separado. El siguiente código es descargar el único objeto del depósito S3.

import boto3 #initiate s3 client s3 = boto3.resource(''s3'') #Download object to the file s3.Bucket(''mybucket'').download_file(''hello.txt'', ''/tmp/hello.txt'')


# 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"