使用 Boto3 从内存上传文件到 S3

Her*_*man 1 amazon-s3 amazon-web-services python-3.x boto3

这个问题已经被问过很多次了,但我的情况却略有不同。我正在尝试创建一个 lambda 来生成 .html 文件并将其上传到 S3。当文件在磁盘上创建时它工作,然后我可以像这样上传它:

boto3.client('s3').upload_file('index.html', bucket_name, 'folder/index.html')
Run Code Online (Sandbox Code Playgroud)

所以现在我必须在内存中创建文件,为此我首先尝试了StringIO()。但是然后.upload_file抛出一个错误。

boto3.client('s3').upload_file(temp_file, bucket_name, 'folder/index.html')
ValueError: Filename must be a string`. 
Run Code Online (Sandbox Code Playgroud)

所以我尝试使用.upload_fileobj()但后来出现错误TypeError: a bytes-like object is required, not 'str'

所以我尝试使用Bytesio(),它希望我首先将 str 转换为字节,所以我做了:

temp_file = BytesIO()
temp_file.write(index_top.encode('utf-8'))
print(temp_file.getvalue())
boto3.client('s3').upload_file(temp_file, bucket_name, 'folder/index.html')
Run Code Online (Sandbox Code Playgroud)

但现在它只是上传一个空文件,尽管.getvalue()清楚地表明它确实有内容。

我究竟做错了什么?

小智 8

但现在它只是上传一个空文件,尽管 .getvalue() 清楚地显示其中确实有内容。

当您完成对文件缓冲区的写入时,该位置保留在末尾。当您上传缓冲区时,它会从当前所在的位置开始。由于您位于末尾,因此您不会获得任何数据。要解决这个问题,您只需要添加一个seek(0),在写入完成后将缓冲区重置回开头。你的代码看起来像这样:

temp_file = BytesIO()
temp_file.write(index_top.encode('utf-8'))
temp_file.seek(0)
print(temp_file.getvalue())
boto3.client('s3').upload_file(temp_file, bucket_name, 'folder/index.html')
Run Code Online (Sandbox Code Playgroud)

  • 请注意,如果您已经有了字符串,您可以直接将其传递到“BytesIO”构造函数中,这将使用给定的数据创建缓冲区,但将位置保留为 0,这样您就无需在字符串中键入所有这些字母。 `seek` 调用。(当然,如果您通过多次调用“write”逐步构建字节缓冲区,则这将不起作用。) (2认同)

Joh*_*ein 5

如果您希望从内存在 Amazon S3 中创建对象,请使用put_object()

import boto3

s3_client = boto3.client('s3')

html = "<h2>Hello World</h2>"

s3_client.put_object(Body=html, Bucket='my-bucket', Key='foo.html', ContentType='text/html')
Run Code Online (Sandbox Code Playgroud)