it-swarm.com.de

So speichern Sie ein S3-Objekt mit boto3 in einer Datei

Ich versuche eine "Hallo Welt" mit dem neuen boto3 client für AWS zu erstellen.

Der Anwendungsfall, den ich habe, ist ziemlich einfach: Holen Sie das Objekt aus S3 und speichern Sie es in der Datei.

In boto 2.X würde ich es so machen:

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

In Boto 3. Ich kann keine saubere Methode finden, um dasselbe zu tun, also durchlaufe ich manuell das "Streaming" -Objekt:

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)

oder

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)

Und es funktioniert gut. Ich habe mich gefragt, gibt es eine "native" boto3-Funktion, die die gleiche Aufgabe erfüllt?

98
Vor

In Boto3 wurde kürzlich eine Anpassung vorgenommen, die (unter anderem) dazu beiträgt. Es ist derzeit auf dem untergeordneten S3-Client verfügbar und kann folgendermaßen verwendet werden:

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

Diese Funktionen behandeln automatisch das Lesen/Schreiben von Dateien sowie das parallele Hochladen mehrerer Dateien für große Dateien.

165
Daniel

boto3 hat jetzt eine schönere Schnittstelle als der Client:

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

Dies ist an sich nicht viel besser als die Variable client in der akzeptierten Antwort (obwohl die Dokumente sagen, dass es besser ist, Uploads und Downloads bei Fehlern erneut durchzuführen), jedoch sind Ressourcen in der Regel ergonomischer (z. B. der s3 bucket) und object resources sind schöner als die Client-Methoden. Dadurch können Sie auf der Ressourcenebene bleiben, ohne herunterfallen zu müssen.

Resources kann im Allgemeinen auf dieselbe Art und Weise wie Clients erstellt werden, und sie verwenden alle oder die meisten der gleichen Argumente und leiten sie einfach an ihre internen Clients weiter.

53
quodlibetor

Für diejenigen von Ihnen, die set_contents_from_string wie boto2-Methoden simulieren möchten, können Sie es versuchen

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

Für Python3:

In python3 sind sowohl StringIO als auch cStringIO weg . Verwenden Sie den StringIO-Import wie folgt:

from io import StringIO

Um beide Versionen zu unterstützen:

try:
   from StringIO import StringIO
except ImportError:
   from io import StringIO
35
cgseller
# 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"
10
Lord Sumner

Hinweis: Ich gehe davon aus, dass Sie die Authentifizierung separat konfiguriert haben. Unter dem folgenden Code können Sie das einzelne Objekt aus dem S3-Bucket herunterladen.  

import boto3

#initiate s3 client 
s3 = boto3.resource('s3')

#Download object to the file    
s3.Bucket('mybucket').download_file('hello.txt', '/tmp/hello.txt')
1
Tushar Niras

Wenn Sie eine Datei mit einer anderen Konfiguration als der Standardkonfiguration lesen möchten, können Sie entweder mpu.aws.s3_download(s3path, destination) direkt oder den kopierten Code verwenden:

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)
0
Martin Thoma