web-dev-qa-db-ja.com

S3.Client.upload_file()とS3.Client.upload_fileobj()の違いは何ですか?

S3.Client.upload_file および S3.Client.upload_fileobj によると、upload_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の方が優れていますか?違いはありますか?

7
Flair

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

その場合、ローカルディスクから読み取る必要がないため、パフォーマンスが向上します。

5
Samuel

TL; DR

速度に関しては、どちらの方法もほぼ同じように実行され、両方ともpythonで記述され、ボトルネックはdisk-io(ディスクからファイルを読み取る)またはnetwork-io(s3に書き込む)のいずれかになります) 。

  • ディスクからのファイルのアップロードのみを処理するコードを記述する場合は、upload_file()を使用します。
  • ディスクのユースケースからのファイルだけでなく、将来再利用される可能性があるs3アップロードを処理するための汎用コードを記述する場合は、upload_fileobj()を使用します。


とにかくfileobjとは何ですか?

python標準ライブラリを含む複数の場所での慣習があります。fileobjという用語を使用している場合、彼女は ファイルのようなオブジェクト を意味します。同じパラメーターとしてファイルパス(str)またはfileobj(ファイルのようなオブジェクト)を取ることができる関数を公開する一部のライブラリーです。

ファイルオブジェクトを使用する場合、コードはディスクのみに限定されません。たとえば、次のようになります。

  1. たとえば、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 一方、2つのパラメーター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)
_
4
ShmulikA

それらは比較できないので、どちらも良くありません。最終結果は同じですが(オブジェクトがS3にアップロードされます)、そのオブジェクトのソースはまったく異なります。 1つはアップロードするファイルのディスク上のパスを指定することを期待し、もう1つはファイルのようなオブジェクトを提供することを期待しています。

ディスクにファイルがあり、それをアップロードする場合は、upload_fileを使用します。ファイルのようなオブジェクト(最終的には、開いているファイル、ストリーム、ソケット、バッファ、文字列など、多くのことになる)がある場合は、upload_fileobjを使用します。

このコンテキストでの「ファイルのようなオブジェクト」は、readメソッドを実装し、バイトを返すものです。

1
jarmod

https://boto3.amazonaws.com/v1/documentation/api/1.9.185/guide/s3-uploading-files.html のドキュメントに従って

"upload_fileメソッドとupload_fileobjメソッドは、S3クライアント、バケット、オブジェクトの各クラスによって提供されます。各クラスが提供するメソッドの機能は同じです。あるクラスのメソッドを別のクラスのメソッドを呼び出すことによる利点はありません。最も便利なクラスを使用してください。」

上記の答えは間違っているようです

1
praveen