Boto3 S3: TypeError: coercing to Unicode: need string or buffer, file found

Boto3 S3: TypeError: coercing to Unicode: need string or buffer, file found

正在尝试将文件上传到 S3:

    # boto3 s3 client
    s3.put_object(Bucket=self.bucket,
                  Body=open(upload_file, 'rb'),
                  Key=k.key,
                  SSECustomerAlgorithm='AES256',
                  SSECustomerKey=base64.b64encode(data_key),
                  SSECustomerKeyMD5=base64.b64encode(data_key_md5)
                  )

并在这一行出现错误:

TypeError: coercing to Unicode: need string or buffer, file found

我的 upload_file 变量是 <type 'file'>dir:

['__class__', '__delattr__', '__doc__', '__enter__', '__exit__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'close', 'closed', 'encoding', 'errors', 'fileno', 'flush', 'isatty', 'mode', 'name', 'newlines', 'next', 'read', 'readinto', 'readline', 'readlines', 'seek', 'softspace', 'tell', 'truncate', 'write', 'writelines', 'xreadlines']

切换到 open(upload_file, 'rb').read() 无济于事。此外,我的文件可能很大(1gb pr 左右),将它们保留为字符串是不合理的。

我知道如果我将 upload_file 设置为文件路径它会起作用,但我没有这个文件在磁盘上,它是通过表单提交的。

更新

这很奇怪,但是当我使用测试文件或字符串(为了测试)时遇到了类似的问题:

TypeError: expected string or buffer

这是对以下内容的回复:

# boto3 s3 client
s3.put_object(Bucket=self.bucket,
    # put existing filr
    Body=open('/tml/existing-file', 'rb'), # adding read() wont help
    # ...
)

字符串相同:

# boto3 s3 client
s3.put_object(Bucket=self.bucket,
    # put existing filr
    Body='some random string',
    # ...
)

我建议您将输入流写入临时文件并使用 Bucket.upload_file 传输文件。在 Web 服务应用程序中将大文件保存在内存中并不好。考虑到您有多个并发上传请求,这总共会消耗大量内存。

import tempfile
import shutil
file_ = file_like_object_from_form_submit
with tempfile.NamedTemporaryFile() as tmpfile:
    shutil.copyfileobj(file_, tmpfile)
    tmpfile.flush()
    self.bucket.upload_file(tmpfile.name, path)

不知道为什么我不能让它与 boto3 一起工作,但这里的代码与以前的 boto2 版本一起工作。唯一的区别是:根据官方文档,您需要在 header 中添加 put 参数: http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html 在我的代码示例中,它看起来像:

    headers.update({
        'x-amz-server-side-encryption-customer-algorithm': 'AES256',
        'x-amz-server-side-encryption-customer-key': base64.b64encode(data_key),
        'x-amz-server-side-encryption-customer-key-MD5': base64.b64encode(data_key_md5)
    })

    k.set_contents_from_file(upload_file, headers=headers)

如您所见,upload_file 在这种情况下工作正常。