S3.Client.upload_file()和S3.Client.upload_fileobj()有什么区别?

时间:2018-09-14 17:43:07

标签: python python-3.x amazon-web-services amazon-s3 boto3

根据https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.upload_filehttps://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.upload_fileobjupload_fileobj听起来可能更快。但是有人知道细节吗?我应该上传文件还是以二进制模式打开文件以使用upload_fileobj?换句话说,

import boto3

s3 = boto3.resource('s3')

### Version 1
s3.meta.client.upload_file('/tmp/hello.txt', 'mybucket', 'hello.txt')

### Version 2
with open('/tmp/hello.txt', 'rb') as data:
    s3.upload_fileobj(data, 'mybucket', 'hello.txt')

第1版或第2版更好吗?有区别吗?

3 个答案:

答案 0 :(得分:4)

TL; DR

就速度而言,这两种方法的性能大致相同,都是用python编写的,而瓶颈将是disk-io(从磁盘读取文件)或network-io(写入s3)。

  • 在编写仅处理从磁盘上载文件的代码时,请使用upload_file()
  • 在编写通用代码来处理s3上传时使用upload_fileobj(),将来可能不仅对磁盘用例中的文件重复使用s3上传。


什么是fileobj?

在很多地方都有约定,包括python标准库,当人们使用术语fileobj时,她的意思是file-like object。 甚至有一些库公开了可以将文件路径(str)或fileobj(类似文件的对象)作为相同参数的函数。

使用文件对象时,您的代码不仅限于磁盘,例如:

  1. 例如,您可以以流方式将数据从一个s3对象复制到另一个对象中(无需使用磁盘空间或减慢对磁盘执行读/写io的过程)。

  2. 在将对象写入S3时,您可以即时(解)压缩或解密数据

将python gzip模块与类文件对象以通用方式一起使用的示例:

import gzip, io

def gzip_greet_file(fileobj):
    """write gzipped hello message to a file"""
    with gzip.open(filename=fileobj, mode='wb') as fp:
        fp.write(b'hello!')

# using opened file
gzip_greet_file(open('/tmp/a.gz', 'wb'))

# using filename from disk
gzip_greet_file('/tmp/b.gz')

# using io buffer
file = io.BytesIO()
gzip_greet_file(file)
file.seek(0)
print(file.getvalue())
另一方面,

tarfile具有两个参数file和fileobj:

tarfile.open(name=None, mode='r', fileobj=None, bufsize=10240, **kwargs)


使用s3.upload_fileobj()即时压缩的示例

import gzip, boto3

s3 = boto3.resource('s3')


def upload_file(fileobj, bucket, key, compress=False):
    if compress:
        fileobj = gzip.GzipFile(fileobj=fileobj, mode='rb')
        key = key + '.gz'
    s3.upload_fileobj(fileobj, bucket, key)

答案 1 :(得分:4)

upload_fileobj的要点是,文件对象不必首先存储在本地磁盘上,而可以表示为RAM中的文件对象。

Python为此目的有standard library module

代码看起来像

import io
fo = io.BytesIO(b'my data stored as file object in RAM')
s3.upload_fileobj(fo, 'mybucket', 'hello.txt')

在这种情况下,由于您不必从本地磁盘读取数据,因此它的执行速度更快。

答案 2 :(得分:1)

根据https://boto3.amazonaws.com/v1/documentation/api/1.9.185/guide/s3-uploading-files.html

中的文档

” upload_file和upload_fileobj方法由S3 Client,Bucket和Object类提供。每个类提供的方法功能是相同的。通过调用一个类的方法来获得另一个类没有任何益处。使用任何一个类最方便。”

以上答案似乎是错误的