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"