Cách ghi tệp hoặc dữ liệu vào đối tượng S3 bằng boto3


104

Trong boto 2, bạn có thể ghi vào một đối tượng S3 bằng các phương pháp sau:

Có tương đương boto 3 không? Phương thức boto3 để lưu dữ liệu vào một đối tượng được lưu trữ trên S3 là gì?

Câu trả lời:


212

Trong boto 3, các phương thức 'Key.set_contents_from_' đã được thay thế bằng

Ví dụ:

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

Ngoài ra, dữ liệu nhị phân có thể đến từ việc đọc tệp, như được mô tả trong các tài liệu chính thức so sánh boto 2 và boto 3 :

Lưu trữ dữ liệu

Dễ dàng lưu trữ dữ liệu từ tệp, luồng hoặc chuỗi:

# 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: Không thể xác định thông tin đăng nhập làm thế nào để khắc phục điều này?
deepak murthy,

2
@deepakmurthy Tôi không chắc tại sao bạn lại gặp lỗi đó ... Bạn cần đặt một câu hỏi Stack Overflow mới và cung cấp thêm chi tiết về sự cố.
jkdev

1
Khi tôi thử, s3.Object().put()tôi kết thúc với một đối tượng bằng không content-length. Đối với tôi put()chỉ chấp nhận dữ liệu chuỗi, nhưng put(str(binarydata)) dường như có một số loại vấn đề mã hóa. Tôi kết thúc với một đối tượng có kích thước gần gấp 3 lần dữ liệu gốc, điều này khiến nó trở nên vô dụng đối với tôi.
user1129682

@ user1129682 Tôi không chắc tại sao lại như vậy. Bạn có thể vui lòng đặt một câu hỏi mới và cung cấp thêm chi tiết?
jkdev

@jkdev Sẽ thật tuyệt nếu bạn có thể xem qua .
user1129682

48

boto3 cũng có một phương pháp tải lên tệp trực tiếp:

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


5
Điều này là tốt, nhưng nó không cho phép lưu trữ dữ liệu hiện có trong bộ nhớ.
Reid

3
@Reid: đối với các tệp trong bộ nhớ, bạn có thể sử dụng s3.Bucket(...).upload_fileobj()phương pháp này để thay thế.
svohara

36

Bạn không còn phải chuyển đổi nội dung sang nhị phân trước khi ghi vào tệp trong S3. Ví dụ sau tạo một tệp văn bản mới (được gọi là newfile.txt) trong một thùng S3 với nội dung chuỗi:

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)

Không biết hành động 'đặt' của tôi không có quyền truy cập. Tôi đã tạo nhóm này và đặt id chuẩn của mình dưới danh sách truy cập.
Chen Lin

Làm thế nào để bạn đưa ra một prefixtrong trường hợp này? Có nghĩa là, nếu bạn muốn lưu trữ tệp trong đó my-bucket-name/subfolder/thì sao?
kev

3
@kev, bạn có thể chỉ định điều đó cùng với tên tệp 'subfolder / newfile.txt' thay vì 'newfile.txt'
Madhava Carrillo

Re "Bạn không còn phải chuyển đổi nội dung sang nhị phân trước khi ghi vào tệp trong S3.", Điều này có được ghi ở đâu đó không? Tôi đang xem boto3.amazonaws.com/v1/documentation/api/latest/reference/… và nghĩ rằng nó chỉ chấp nhận byte. Tôi không chắc chính xác điều gì tạo nên "đối tượng giống tệp có thể tìm kiếm", nhưng không nghĩ rằng điều đó bao gồm các chuỗi.
Emma

Tôi có thể đã so sánh điều này với download_fileobj () để tải lên tệp nhiều phần lớn. Các phương thức tải lên yêu cầu các đối tượng tệp có thể tìm kiếm , nhưng put () cho phép bạn viết chuỗi trực tiếp vào tệp trong thùng, điều này rất tiện lợi cho các hàm lambda để tạo và ghi động các tệp vào thùng S3.
Franke

28

Đây là một mẹo hay để đọc JSON từ 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))

Bây giờ bạn có thể sử dụng json.load_s3json.dump_s3với cùng một API như loaddump

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
Thông minh. Để có được nó để làm việc, tôi đã thêm chút thêm này: ...["Body"].read().decode('utf-8').
sedeh

Ý tưởng tuyệt vời. Dù sao, nó cung cấp một số không gian để cải tiến việc đặt tên.
Jan Vlcinsky

Đề xuất viết lại ý tưởng hay này: gist.github.com/vlcinsky/bbeda4321208aa98745afc29b58e90ac
Jan Vlcinsky

12

Một phiên bản ngắn gọn và rõ ràng hơn mà tôi sử dụng để tải tệp lên nhanh chóng vào một nhóm và thư mục con S3 cụ thể-

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

Lưu ý : Bạn LUÔN LUÔN phải đặt thông tin đăng nhập AWS của mình ( aws_access_key_idaws_secret_access_key) vào một tệp riêng biệt, ví dụ:~/.aws/credentials


Vị trí tương đương của Windows cho tệp thông tin đăng nhập AWS là gì, vì Windows sẽ không hỗ trợ~
Hamman Samuel

1
@HammanSamuel bạn có thể lưu trữ nó như thế nàoC:\Users\username\.aws\credentials
kev

1

điều đáng nói là mở thông minh sử dụngboto3 như một back-end.

smart-openlà một thả thay thế cho của python opencó thể mở tập tin từ s3, cũng như ftp,http và nhiều giao thức khác.

ví dụ

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

Thông tin đăng nhập aws được tải qua thông tin đăng nhập boto3 , thường là một tệp trong ~/.aws/dir hoặc một biến môi trường.


1
trong khi sự phản hồi này mang tính thông tin, nó không tuân theo việc trả lời câu hỏi ban đầu - đó là, boto3 tương đương với các phương pháp boto nhất định là gì.
robinhood91

1
Sử dụng mở thông minh boto3
Uri Goren

1

Bạn có thể sử dụng mã dưới đây để viết, ví dụ: một hình ảnh cho S3 vào năm 2019. Để có thể kết nối với S3, bạn sẽ phải cài đặt AWS CLI bằng lệnh pip install awscli, sau đó nhập một số thông tin đăng nhập bằng lệnh 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.