So schreiben Sie mit boto3 eine Datei oder Daten in ein S3-Objekt


Antworten:


210

In Boto 3 wurden die Methoden 'Key.set_contents_from_' durch ersetzt

Beispielsweise:

import boto3

some_binary_data = b'Here we have some data'
more_binary_data = b'Here we have some more data'

# Method 1: Object.put()
s3 = boto3.resource('s3')
object = s3.Object('my_bucket_name', 'my/key/including/filename.txt')
object.put(Body=some_binary_data)

# Method 2: Client.put_object()
client = boto3.client('s3')
client.put_object(Body=more_binary_data, Bucket='my_bucket_name', Key='my/key/including/anotherfilename.txt')

Alternativ können die Binärdaten aus dem Lesen einer Datei stammen, wie in den offiziellen Dokumenten zum Vergleich von Boto 2 und Boto 3 beschrieben :

Daten speichern

Das Speichern von Daten aus einer Datei, einem Stream oder einer Zeichenfolge ist einfach:

# Boto 2.x
from boto.s3.key import Key
key = Key('hello.txt')
key.set_contents_from_file('/tmp/hello.txt')

# Boto 3
s3.Object('mybucket', 'hello.txt').put(Body=open('/tmp/hello.txt', 'rb'))

botocore.exceptions.NoCredentialsError: Anmeldeinformationen können nicht gefunden werden. Wie kann das behoben werden?
Deepak Murthy

2
@deepakmurthy Ich bin nicht sicher , warum Sie diesen Fehler bekommen ... Sie müssen , um eine neue Stack - Überlauf Frage stellen und weitere Informationen über das Thema geben.
JKDEV

1
Wenn ich es versuche, erhalte s3.Object().put()ich ein Objekt mit Null content-length. Für mich put()akzeptiert nur String-Daten, put(str(binarydata)) scheint aber einige Codierungsprobleme zu haben. Am Ende habe ich ein Objekt, das ungefähr dreimal so groß ist wie die Originaldaten, was es für mich unbrauchbar macht.
Benutzer1129682

@ user1129682 Ich bin mir nicht sicher, warum das so ist. Könnten Sie bitte eine neue Frage stellen und weitere Details angeben?
JKDEV

@jkdev Es wäre toll, wenn Sie einen Blick darauf werfen könnten .
user1129682


36

Sie müssen den Inhalt nicht mehr in Binär konvertieren, bevor Sie in S3 in die Datei schreiben. Im folgenden Beispiel wird eine neue Textdatei (newfile.txt) in einem S3-Bucket mit Zeichenfolgeninhalt erstellt:

import boto3

s3 = boto3.resource(
    's3',
    region_name='us-east-1',
    aws_access_key_id=KEY_ID,
    aws_secret_access_key=ACCESS_KEY
)
content="String content to write to a new S3 file"
s3.Object('my-bucket-name', 'newfile.txt').put(Body=content)

Habe keine Ahnung, dass meine 'Put'-Aktion keinen Zugriff hat. Ich habe diesen Bucket erstellt und meine kanonische ID unter die Zugriffsliste gesetzt.
Chen Lin

Wie geben Sie prefixin diesem Fall eine? Was ist, wenn Sie die Datei speichern möchten my-bucket-name/subfolder/?
Kev

3
@kev können Sie angeben, dass zusammen mit dem Dateinamen 'Unterordner / newfile.txt' anstelle von 'newfile.txt'
Madhava Carrillo

Betreff "Sie müssen den Inhalt nicht mehr in Binär konvertieren, bevor Sie in die Datei in S3 schreiben.", Ist dies irgendwo dokumentiert? Ich habe mir boto3.amazonaws.com/v1/documentation/api/latest/reference/… angesehen und dachte, es werden nur Bytes akzeptiert. Ich bin mir nicht sicher, was genau ein "durchsuchbares dateiähnliches Objekt" ausmacht, habe aber nicht gedacht, dass dies Zeichenfolgen enthält.
Emma

Möglicherweise habe ich dies mit download_fileobj () verglichen, das für große mehrteilige Datei-Uploads vorgesehen ist. Für die Upload-Methoden sind durchsuchbare Dateiobjekte erforderlich. Mit put () können Sie jedoch Zeichenfolgen direkt in eine Datei im Bucket schreiben. Dies ist praktisch, damit Lambda-Funktionen Dateien dynamisch erstellen und in einen S3-Bucket schreiben können.
Franke

28

Hier ist ein schöner Trick, um JSON von s3 zu lesen:

import json, boto3
s3 = boto3.resource("s3").Bucket("bucket")
json.load_s3 = lambda f: json.load(s3.Object(key=f).get()["Body"])
json.dump_s3 = lambda obj, f: s3.Object(key=f).put(Body=json.dumps(obj))

Jetzt können Sie json.load_s3und json.dump_s3mit derselben API wie loadund verwendendump

data = {"test":0}
json.dump_s3(data, "key") # saves json to s3://bucket/key
data = json.load_s3("key") # read json from s3://bucket/key

2
Ausgezeichnet. Damit es funktioniert, habe ich dieses zusätzliche Bit hinzugefügt : ...["Body"].read().decode('utf-8').
Sedeh

Großartige Idee. Auf jeden Fall bietet es Platz für Namensverbesserungen.
Jan Vlcinsky

Vorgeschlagene Neufassung dieser schönen Idee: gist.github.com/vlcinsky/bbeda4321208aa98745afc29b58e90ac
Jan Vlcinsky

12

Eine übersichtlichere und übersichtlichere Version, mit der ich Dateien im laufenden Betrieb in einen bestimmten S3-Bucket und Unterordner hochlade.

import boto3

BUCKET_NAME = 'sample_bucket_name'
PREFIX = 'sub-folder/'

s3 = boto3.resource('s3')

# Creating an empty file called "_DONE" and putting it in the S3 bucket
s3.Object(BUCKET_NAME, PREFIX + '_DONE').put(Body="")

Hinweis : Sie sollten Ihre AWS-Anmeldeinformationen ( aws_access_key_idund aws_secret_access_key) IMMER in einer separaten Datei ablegen, z.~/.aws/credentials


Was ist der Windows-äquivalente Speicherort für die AWS-Anmeldeinformationsdatei, da Windows dies nicht unterstützt~
Hamman Samuel,

1
@ HammanSamuel Sie können es speichern wieC:\Users\username\.aws\credentials
kev

1

Erwähnenswert ist Smart-Open , das boto3als Backend verwendet wird .

smart-openist ein Drop-in - Ersatz für Python , opendie Dateien aus öffnen kann s3, sowie ftp, httpund viele andere Protokolle.

beispielsweise

from smart_open import open
import json
with open("s3://your_bucket/your_key.json", 'r') as f:
    data = json.load(f)

Die aws-Anmeldeinformationen werden über boto3-Anmeldeinformationen geladen , normalerweise eine Datei im Verzeichnis~/.aws/ oder eine Umgebungsvariable.


1
Diese Antwort ist zwar informativ, entspricht jedoch nicht der Beantwortung der ursprünglichen Frage: Was sind die Boto3-Äquivalente bestimmter Boto-Methoden?
Robinhood91

1
Smart Open verwendet boto3
Uri Goren

1

Sie können den folgenden Code verwenden, um beispielsweise ein Image in S3 im Jahr 2019 zu schreiben. Um eine Verbindung zu S3 herstellen zu können, müssen Sie AWS CLI mit dem Befehl installieren pip install awscliund anschließend mit dem Befehl einige Anmeldeinformationen eingeben aws configure:

import urllib3
import uuid
from pathlib import Path
from io import BytesIO
from errors import custom_exceptions as cex

BUCKET_NAME = "xxx.yyy.zzz"
POSTERS_BASE_PATH = "assets/wallcontent"
CLOUDFRONT_BASE_URL = "https://xxx.cloudfront.net/"


class S3(object):
    def __init__(self):
        self.client = boto3.client('s3')
        self.bucket_name = BUCKET_NAME
        self.posters_base_path = POSTERS_BASE_PATH

    def __download_image(self, url):
        manager = urllib3.PoolManager()
        try:
            res = manager.request('GET', url)
        except Exception:
            print("Could not download the image from URL: ", url)
            raise cex.ImageDownloadFailed
        return BytesIO(res.data)  # any file-like object that implements read()

    def upload_image(self, url):
        try:
            image_file = self.__download_image(url)
        except cex.ImageDownloadFailed:
            raise cex.ImageUploadFailed

        extension = Path(url).suffix
        id = uuid.uuid1().hex + extension
        final_path = self.posters_base_path + "/" + id
        try:
            self.client.upload_fileobj(image_file,
                                       self.bucket_name,
                                       final_path
                                       )
        except Exception:
            print("Image Upload Error for URL: ", url)
            raise cex.ImageUploadFailed

        return CLOUDFRONT_BASE_URL + id
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.