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

Python S3.Client.upload_file()和S3.Client.upload_fileobj()之间有什么区别?,python,python-3.x,amazon-web-services,amazon-s3,boto3,Python,Python 3.x,Amazon Web Services,Amazon S3,Boto3,根据和,upload\u fileobj可能听起来更快。但有人知道具体情况吗?我应该只上传文件,还是以二进制模式打开文件以使用upload\u 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.tx

根据和,
upload\u fileobj
可能听起来更快。但有人知道具体情况吗?我应该只上传文件,还是以二进制模式打开文件以使用
upload\u 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更好?有区别吗?

两者都不好,因为它们不可比。虽然最终结果是相同的(一个对象被上传到S3),但它们对该对象的来源却完全不同。一个期望您提供要上载的文件在磁盘上的路径,而另一个期望您提供类似文件的对象

如果您在磁盘上有一个文件,并且想要上传它,那么使用
upload\u file
。如果您有一个类似文件的对象(最终可能是很多东西,包括打开的文件、流、套接字、缓冲区、字符串),那么使用
upload\u fileobj

在此上下文中,“类文件对象”是实现
read
方法并返回字节的任何对象。

TL;博士 就速度而言,两种方法的性能大致相同,都是用python编写的,瓶颈是磁盘io(从磁盘读取文件)或网络io(写入s3)

  • 编写仅处理从磁盘上载文件的代码时,请使用
    upload\u file()
  • 当您编写处理s3上传的通用代码时,请使用
    upload\u fileobj()
    ,这些代码将来可能会被重用,而不仅仅用于磁盘文件用例

fileobj到底是什么? 在包括python标准库在内的多个地方都有一个惯例,即当使用术语
fileobj
时,她的意思是。 甚至有些库公开的函数可以将文件路径(str)或fileobj(类似文件的对象)作为相同的参数

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

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

  • 在将对象写入S3时,可以动态地(反)压缩或解密数据

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

    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())
    
    另一方面,有两个参数file&fileobj:

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

    使用
    s3.upload\u fileobj()

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

    Python为此目的提供了一些支持

    代码如下所示

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

    在这种情况下,它将执行得更快,因为您不必从本地磁盘读取数据。

    如中的文档所示

    upload_file和upload_fileobj方法由S3客户端、Bucket和对象类提供。每个类提供的方法功能相同。调用一个类的方法而不是另一个类的方法不会获得任何好处。请使用最方便的类


    上面的答案似乎是错误的

    我的使用涉及csv文件,因此由于python
    csv
    库不能很好地处理字节,我想我应该只使用
    s3。为了方便起见,上传文件
    。上面的示例可以与字节和str一起使用,只要正确地更改模式即可。顺便说一句,csv模块接受文件对象,因此无论哪种方式,您都应该手动打开文件。在任何情况下,实现的好运气似乎表明在
    Python3
    中使用
    csv
    很麻烦。csv到底有什么麻烦?线程上的第一个答案似乎对OP有所帮助。在python中如何处理csv?如果您有关于csv处理的更多问题,您可能希望打开另一个问题,以便我们可以帮助您。上述答案并非100%正确。请参考相同的源代码状态:
    upload\u file方法接受文件名、bucket名和对象名。该方法通过将大型文件拆分为较小的块并并行上载每个块来处理大型文件。
    上载\u fileobj方法接受一个可读的类似文件的对象。文件对象必须以二进制模式打开,而不是以文本模式打开。
    上面回答了这个问题。
    import io
    fo = io.BytesIO(b'my data stored as file object in RAM')
    s3.upload_fileobj(fo, 'mybucket', 'hello.txt')