Boto3 kullanarak bir S3 nesnesine dosya veya veri nasıl yazılır


Yanıtlar:


219

Boto 3'te 'Key.set_contents_from_' yöntemlerinin yerini

Örneğin:

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

Alternatif olarak, ikili veriler, boto 2 ve boto 3'ü karşılaştıran resmi belgelerde açıklandığı gibi bir dosyanın okunmasından da gelebilir :

Veri depolama

Bir dosyadan, akıştan veya dizeden veri depolamak kolaydır:

# 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: Kimlik bilgileri bulunamıyor, bu nasıl düzeltilir?
deepak murthy

2
@deepakmurthy Bu hatayı neden aldığınızdan emin değilim ... Yeni bir Stack Overflow sorusu sormanız ve sorunla ilgili daha fazla ayrıntı sağlamanız gerekir.
jkdev

1
Denediğimde s3.Object().put()sıfır olan bir nesne buluyorum content-length. Benim için put()yalnızca dizi verilerini kabul ediyor, ancak put(str(binarydata)) bazı kodlama sorunları var gibi görünüyor. Orijinal verinin kabaca 3 katı büyüklüğünde bir nesne elde ediyorum, bu da onu benim için işe yaramaz hale getiriyor.
user1129682

@ user1129682 Bunun neden olduğundan emin değilim. Lütfen yeni bir soru sorabilir ve daha fazla ayrıntı verebilir misiniz ?
jkdev

Eğer eğer @jkdev harika olur bir göz atın .
user1129682


40

Artık S3'teki dosyaya yazmadan önce içerikleri ikiliye dönüştürmeniz gerekmiyor. Aşağıdaki örnek, bir S3 klasöründe dize içerikli yeni bir metin dosyası (newfile.txt olarak adlandırılır) oluşturur:

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)

Hiçbir fikrim yok benim 'koy' eylemimin erişimi yok. Bu paketi oluşturdum ve kanonik kimliğimi erişim listesinin altına koydum.
Chen Lin

prefixBu durumda nasıl a verirsiniz ? Anlamı, dosyayı saklamak istersen ne olur my-bucket-name/subfolder/?
kev

3
@kev, 'newfile.txt' yerine 'subfolder / newfile.txt' dosya adı ile birlikte belirtebilirsiniz
Madhava Carrillo

Yeniden "Artık, S3'teki dosyaya yazmadan önce içeriği ikiliye dönüştürmeniz gerekmiyor.", Bu bir yerde belgelendi mi? Boto3.amazonaws.com/v1/documentation/api/latest/reference/… 'a bakıyordum ve sadece baytları kabul ettiğini düşündüm. Tam olarak neyin "aranabilir dosya benzeri nesneyi" oluşturduğundan emin değilim, ancak dizeleri içerdiğini düşünmedim.
Emma

Bunu, büyük çok parçalı dosya yüklemeleri için olan download_fileobj () ile karşılaştırmış olabilirim. Yükleme yöntemleri, aranabilir dosya nesneleri gerektirir , ancak put (), dizeleri doğrudan klasördeki bir dosyaya yazmanıza olanak tanır. Bu, lambda işlevlerinin dinamik olarak dosya oluşturup bir S3 klasörüne yazması için kullanışlıdır.
Franke

28

JSON'u s3'ten okumak için güzel bir numara:

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

Artık json.load_s3ve json.dump_s3ile aynı API'yi kullanabilirsiniz loadvedump

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
Mükemmel. İşe almak için, bu ilave bit ekledi: ...["Body"].read().decode('utf-8').
sedeh

İyi fikir. Her neyse, adlandırma iyileştirmeleri için biraz alan sağlar.
Jan Vlcinsky

Bu güzel fikrin yeniden yazılması önerildi: gist.github.com/vlcinsky/bbeda4321208aa98745afc29b58e90ac
Jan Vlcinsky

15

Dosyaları anında belirli bir S3 klasörüne ve alt klasörüne yüklemek için kullandığım daha temiz ve kısa bir sürüm

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

Not : DAİMA AWS kimlik bilgilerinizi ( aws_access_key_idve aws_secret_access_key) ayrı bir dosyaya koymalısınız , örneğin-~/.aws/credentials


Windows desteklemediğinden, AWS kimlik bilgileri dosyası için Windows eşdeğer konumu nedir~
Hamman Samuel

1
Gibi saklayabilirsiniz @HammanSamuelC:\Users\username\.aws\credentials
kev

2

kullanan smart- open'dan bahsetmeye değerboto3arka uç olarak .

smart-openBir açılan yerine piton yıllardan içindir opendosyaları açabilirsiniz s3yanı sıra ftp,http ve diğer birçok protokoller.

Örneğin

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

Aws kimlik bilgileri boto3 kimlik bilgileri aracılığıyla yüklenir , genellikle ~/.aws/dizin içindeki bir dosya veya bir ortam değişkeni.


1
bu yanıt bilgilendirici olmakla birlikte, asıl soruyu yanıtlamaya uymuyor - yani belirli boto yöntemlerinin boto3 karşılıkları nelerdir?
robinhood91

2
Akıllı açık boto3 kullanıyor
Uri Goren

1

Örneğin 2019'da S3'e bir görüntü yazmak için aşağıdaki kodu kullanabilirsiniz. S3'e bağlanabilmek için komut kullanarak AWS CLI'yi yüklemeniz pip install awscli, ardından komut kullanarak birkaç kimlik bilgisi girmeniz gerekir 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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.