Cara menulis file atau data ke objek S3 menggunakan boto3

Jawaban:

212

Di boto 3, metode 'Key.set_contents_from_' diganti dengan

Sebagai contoh:

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

Sebagai alternatif, data biner dapat berasal dari membaca file, seperti yang dijelaskan dalam dokumen resmi yang membandingkan boto 2 dan boto 3 :

Menyimpan Data

Menyimpan data dari file, aliran, atau string itu mudah:

# 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'))
jkdev
sumber
botocore.exceptions.NoCredentialsError: Tidak dapat menemukan kredensial bagaimana cara memperbaikinya?
deepak murthy
2
@deepakmurthy Saya tidak yakin mengapa Anda mendapatkan kesalahan itu ... Anda perlu mengajukan pertanyaan Stack Overflow baru dan memberikan detail selengkapnya tentang masalah tersebut.
jkdev
1
Ketika saya mencoba, s3.Object().put()saya berakhir dengan sebuah objek dengan nol content-length. Bagi saya put()hanya menerima data string, tetapi put(str(binarydata)) tampaknya memiliki semacam masalah pengkodean. Saya berakhir dengan objek kira-kira 3 kali ukuran data asli, yang membuatnya tidak berguna bagi saya.
user1129682
@ user1129682 Saya tidak yakin mengapa demikian. Bisakah Anda mengajukan pertanyaan baru dan memberikan detail lebih lanjut?
jkdev
@jkdev Akan sangat bagus jika Anda bisa melihatnya .
user1129682
49

boto3 juga memiliki metode untuk mengunggah file secara langsung:

s3.Bucket('bucketname').upload_file('/local/file/here.txt','folder/sub/path/to/s3key')

http://boto3.readthedocs.io/en/latest/reference/services/s3.html#S3.Bucket.upload_file

EM Bee
sumber
5
Ini bagus, tetapi tidak memungkinkan data yang ada di memori untuk disimpan.
Reid
3
@Reid: untuk file dalam memori Anda dapat menggunakan s3.Bucket(...).upload_fileobj()metode ini.
svohara
37

Anda tidak lagi harus mengonversi konten ke biner sebelum menulis ke file di S3. Contoh berikut membuat file teks baru (disebut newfile.txt) di bucket S3 dengan konten string:

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)
Franke
sumber
Tidak tahu tindakan 'put' saya tidak memiliki akses. Saya membuat keranjang ini dan meletakkan ID kanonis saya di bawah daftar akses.
Chen Lin
Bagaimana Anda memberi prefixdalam kasus ini? Artinya, bagaimana jika Anda ingin menyimpan file tersebut my-bucket-name/subfolder/?
kev
3
@kev Anda dapat menentukannya bersama dengan nama file 'subfolder / newfile.txt' alih-alih 'newfile.txt'
Madhava Carrillo
Re "Anda tidak lagi harus mengubah konten ke biner sebelum menulis ke file di S3.", Apakah ini didokumentasikan di suatu tempat? Saya melihat boto3.amazonaws.com/v1/documentation/api/latest/reference/… , dan mengira itu hanya menerima byte. Saya tidak yakin apa sebenarnya yang dimaksud dengan "objek seperti file yang dapat dicari", tetapi tidak berpikir itu termasuk string.
Emma
Saya mungkin telah membandingkan ini dengan download_fileobj () yang untuk unggahan file banyak bagian. Metode unggahan memerlukan objek file yang dapat dicari , tetapi put () memungkinkan Anda menulis string langsung ke file di bucket, yang berguna untuk fungsi lambda untuk membuat dan menulis file secara dinamis ke bucket S3.
Franke
28

Inilah trik bagus untuk membaca JSON dari s3:

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

Sekarang Anda dapat menggunakan json.load_s3dan json.dump_s3dengan API yang sama dengan loaddandump

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
Uri Goren
sumber
2
Luar biasa. Untuk mendapatkannya bekerja, saya menambahkan sedikit tambahan ini: ...["Body"].read().decode('utf-8').
sedeh
Ide yang hebat. Bagaimanapun, ini memberikan beberapa ruang untuk perbaikan penamaan.
Jan Vlcinsky
Usulan penulisan ulang dari ide bagus ini: gist.github.com/vlcinsky/bbeda4321208aa98745afc29b58e90ac
Jan Vlcinsky
14

Versi yang lebih bersih dan ringkas yang saya gunakan untuk mengunggah file dengan cepat ke bucket dan sub-folder S3 tertentu-

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="")

Catatan : Anda harus SELALU meletakkan kredensial AWS Anda ( aws_access_key_iddan aws_secret_access_key) di file terpisah, misalnya-~/.aws/credentials

kev
sumber
Apa lokasi setara Windows untuk file kredensial AWS, karena Windows tidak mendukung~
Hamman Samuel
1
@HammanSamuel Anda dapat menyimpannya sepertiC:\Users\username\.aws\credentials
kev
1

perlu menyebutkan smart-open yang digunakan boto3sebagai back-end.

smart-openadalah pengganti drop-in untuk python openyang dapat membuka file dari s3, serta ftp, httpdan banyak protokol lainnya.

sebagai contoh

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

Kredensial aws dimuat melalui kredensial boto3 , biasanya file di ~/.aws/dir atau variabel lingkungan.

Uri Goren
sumber
1
Meskipun jawaban ini informatif, jawaban tersebut tidak sesuai untuk menjawab pertanyaan asli - yaitu, apa persamaan boto3 dari metode boto tertentu.
robinhood91
1
Buka pintar menggunakan boto3
Uri Goren
1

Anda dapat menggunakan kode di bawah ini untuk menulis, misalnya gambar ke S3 pada tahun 2019. Untuk dapat terhubung ke S3 Anda harus menginstal AWS CLI menggunakan perintah pip install awscli, lalu masukkan beberapa kredensial menggunakan perintah 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
Prateek Bhuwania
sumber