web-dev-qa-db-fra.com

Quelle est la différence entre S3.Client.upload_file () et S3.Client.upload_fileobj ()?

Selon S3.Client.upload_file et S3.Client.upload_fileobj , upload_fileobj peut sonner plus rapidement. Mais quelqu'un connaît-il les détails? Dois-je simplement télécharger le fichier ou dois-je l'ouvrir en mode binaire pour utiliser upload_fileobj? En d'autres termes,

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

La version 1 ou la version 2 est-elle meilleure? Y a-t-il une différence?

7
Flair

Le point principal avec upload_fileobj est que l'objet fichier ne doit pas être stocké sur le disque local en premier lieu, mais peut être représenté comme un objet fichier dans la RAM.

Python a module de bibliothèque standard à cet effet.

Le code ressemblera à

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

Dans ce cas, il fonctionnera plus rapidement, car vous n'avez pas à lire à partir du disque local.

5
Samuel

TL; DR

en termes de vitesse, les deux méthodes fonctionneront à peu près de la même manière, toutes deux écrites en python et le goulot d'étranglement sera soit disk-io (lire le fichier depuis le disque) ou network-io (écrire dans s3) .

  • utilisez upload_file() lors de l'écriture de code qui ne gère que le téléchargement de fichiers à partir du disque.
  • utilisez upload_fileobj() lorsque vous écrivez du code générique pour gérer le téléchargement s3 qui peut être réutilisé à l'avenir pour non seulement les fichiers du disque.


Qu'est-ce que fileobj de toute façon?

il existe une convention à plusieurs endroits, y compris la bibliothèque python standard, que lorsque l'on utilise le terme fileobj elle signifie objet de type fichier . Il y a même certaines bibliothèques exposant des fonctions qui peuvent prendre le chemin de fichier (str) ou fileobj (objet de type fichier) comme le même paramètre.

lorsque vous utilisez un objet fichier, votre code n'est pas limité au disque uniquement, par exemple:

  1. par exemple, vous pouvez copier des données d'un objet s3 dans un autre en mode streaming (sans utiliser d'espace disque ni ralentir le processus de lecture/écriture io sur disque).

  2. vous pouvez (dé) compresser ou déchiffrer des données à la volée lors de l'écriture d'objets sur S3

exemple utilisant python gzip module avec un objet de type fichier de manière générique:

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 d'autre part a deux paramètres file & fileobj:

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


Exemple de compression à la volée avec 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

Ni l'un ni l'autre n'est meilleur, car ils ne sont pas comparables. Bien que le résultat final soit le même (un objet est téléchargé sur S3), ils source cet objet assez différemment. L'un s'attend à ce que vous fournissiez le chemin sur le disque du fichier à télécharger tandis que l'autre s'attend à ce que vous fournissiez un objet de type fichier.

Si vous avez un fichier sur le disque et que vous souhaitez le télécharger, utilisez upload_file. Si vous avez un objet semblable à un fichier (qui pourrait finalement être beaucoup de choses, y compris un fichier ouvert, un flux, un socket, un tampon, une chaîne), utilisez upload_fileobj.

Un "objet de type fichier" dans ce contexte est tout ce qui implémente la méthode read et renvoie des octets.

1
jarmod

Selon la documentation de https://boto3.amazonaws.com/v1/documentation/api/1.9.185/guide/s3-uploading-files.html

"Les méthodes upload_file et upload_fileobj sont fournies par les classes S3 Client, Bucket et Object. La fonctionnalité de méthode fournie par chaque classe est identique. Aucun avantage n'est obtenu en appelant la méthode d'une classe par rapport à une autre. Utilisez la classe la plus pratique. "

Les réponses ci-dessus semblent fausses

1
praveen