如何使用boto3将文件或数据写入S3对象


Answers:


211

在Boto 3中,“ Key.set_contents_from_”方法被替换为

例如:

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

另外,二进制数据可以来自读取文件,如官方文档中比较boto 2和boto 3所述

储存资料

从文件,流或字符串存储数据很容易:

# 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:无法找到凭证如何解决?
迪帕克·穆西

2
@deepakmurthy我不确定为什么会收到该错误...您需要询问一个新的Stack Overflow问题,并提供有关该问题的更多详细信息。
jkdev

1
当我尝试时,s3.Object().put()我最终得到一个零值的对象content-length。对我来说,put()只接受字符串数据,但put(str(binarydata)) 似乎存在某种编码问题。我最终得到的对象大约是原始数据大小的3倍,这对我来说毫无用处。
user1129682

@ user1129682我不确定为什么会这样。您能否提出一个新问题并提供更多详细信息?
jkdev

@jkdev如果您可以看一下,那就太好
user1129682


36

在S3中写入文件之前,您不再需要将内容转换为二进制文件。以下示例在具有字符串内容的S3存储桶中创建一个新的文本文件(称为newfile.txt):

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)

不知道我的“放置”操作无法访问。我创建了这个存储桶,并将我的规范ID放在访问列表下。
陈琳

prefix在这种情况下,您如何给?意思是,如果要将文件存储在my-bucket-name/subfolder/哪里?
kev

3
@kev,您可以指定文件名“ subfolder / newfile.txt”而不是“ newfile.txt”
Madhava Carrillo

关于“您不再需要在写入S3中的文件之前将内容转换为二进制文件。”,这是否记录在某处?我当时在看boto3.amazonaws.com/v1/documentation/api/latest/reference/…,并认为它只接受字节。我不确定究竟是什么构成“可搜索的文件状对象”,但并不认为其中包含字符串。
艾玛

我可能会将它与用于大型分段文件上传的download_fileobj()进行了比较。上载方法需要可搜索的文件对象,但是put()允许您将字符串直接写入存储桶中的文件,这对于lambda函数动态创建文件并将其写入S3存储桶非常方便。
弗兰克

28

这是一个从s3读取JSON的好技巧:

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

现在你可以使用json.load_s3json.dump_s3使用相同的API 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
优秀的。为了使其正常工作,我添加了以下额外内容:...["Body"].read().decode('utf-8')
sedeh

好想法。无论如何,它为命名改进提供了一些空间。
Jan Vlcinsky


12

简洁明了的版本,可用于将文件动态上传到给定的S3存储桶和子文件夹-

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

注意:您应始终将AWS凭证(aws_access_key_idaws_secret_access_key)放在单独的文件中,例如-~/.aws/credentials


Windows不支持AWS凭证文件的等效位置,因为Windows不支持~
Hamman Samuel

1
@HammanSamuel,您可以将其存储为C:\Users\username\.aws\credentials
kev

1

值得一提boto3用作后端的智能开放

smart-open是一个下拉更换为Python的open,可以从打开的文件s3,以及ftphttp和许多其他协议。

例如

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

aws凭证通过boto3凭证(通常是~/.aws/dir中的文件或环境变量)加载。


1
尽管此响应很有用,但它并没有坚持回答原始问题-即某些boto方法的boto3等价物是什么。
robinhood91

1
智能开放使用boto3
Uri Goren

1

您可能会使用以下代码进行写操作,例如在2019年将图像写入S3。要连接到S3,您将必须使用command安装AWS CLI pip install awscli,然后使用command 输入少量凭证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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.