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?
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.
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.
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
# 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"
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')
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)