J'ai un fichier CSV en S3 et j'essaie de lire la ligne d'en-tête pour obtenir la taille (ces fichiers sont créés par nos utilisateurs et peuvent donc être de n'importe quelle taille). Y a-t-il un moyen de faire cela en utilisant boto? Je pensais que je pourrais peut-être utiliser un BufferReader en python, mais je n'arrive pas à comprendre comment ouvrir un flux à partir d'une clé S3. Toute suggestion sera appréciée. Merci!
Il semble que boto ait une fonction read()
capable de le faire. Voici un code qui fonctionne pour moi:
>>> import boto
>>> from boto.s3.key import Key
>>> conn = boto.connect_s3('ap-southeast-2')
>>> bucket = conn.get_bucket('bucket-name')
>>> k = Key(bucket)
>>> k.key = 'filename.txt'
>>> k.open()
>>> k.read(10)
'This text '
L'appel à read(n)
renvoie les n prochains octets de l'objet.
Bien sûr, cela ne retournera pas automatiquement "la ligne d'en-tête", mais vous pouvez l'appeler avec un nombre suffisamment grand pour renvoyer la ligne d'en-tête au minimum.
Vous pouvez trouver https://pypi.python.org/pypi/smart_open utile pour votre tâche.
De la documentation:
for line in smart_open.smart_open('s3://mybucket/mykey.txt'):
print line
Voici une solution qui diffuse les données ligne par ligne:
from io import TextIOWrapper
from gzip import GzipFile
...
# get StreamingBody from botocore.response
response = s3.get_object(Bucket=bucket, Key=key)
# if gzipped
gzipped = GzipFile(None, 'rb', fileobj=response['Body'])
data = TextIOWrapper(gzipped)
for line in data:
# process line
Avec boto3, vous pouvez accéder à un flux brut et lire ligne par ligne ..__ Notez que le flux brut est une propriété privée pour une raison quelconque
s3 = boto3.resource('s3', aws_access_key_id='xxx', aws_secret_access_key='xxx')
obj = s3.Object('bucket name', 'file key')
obj.get()['Body']._raw_stream.readline() # line 1
obj.get()['Body']._raw_stream.readline() # line 2
obj.get()['Body']._raw_stream.readline() # line 3...
Utiliser boto3:
s3 = boto3.resource('s3')
obj = s3.Object(BUCKET, key)
for line in obj.get()['Body']._raw_stream:
# do something with line
Si vous souhaitez lire plusieurs fichiers (ligne par ligne) avec un préfixe de compartiment spécifique (c'est-à-dire dans un "sous-dossier"), vous pouvez procéder comme suit:
s3 = boto3.resource('s3', aws_access_key_id='<key_id>', aws_secret_access_key='<access_key>')
bucket = s3.Bucket('<bucket_name>')
for obj in bucket.objects.filter(Prefix='<your prefix>'):
for line in obj.get()['Body'].read().splitlines():
print(line.decode('utf-8'))
Ici les lignes sont des octets alors je les décode; mais si elles sont déjà une chaîne, vous pouvez ignorer cela.
Le moyen le plus dynamique et le moins coûteux de lire le fichier est de lire chaque octet jusqu'à ce que vous trouviez le nombre de lignes dont vous avez besoin.
line_count = 0
line_data_bytes = b''
while line_count < 2 :
incoming = correlate_file_obj['Body'].read(1)
if incoming == b'\n':
line_count = line_count + 1
line_data_bytes = line_data_bytes + incoming
logger.debug("read bytes:")
logger.debug(line_data_bytes)
line_data = line_data_bytes.split(b'\n')
Vous n'aurez pas besoin de deviner la taille de l'en-tête si celle-ci peut changer, vous ne finirez pas par télécharger tout le fichier et vous n'avez pas besoin d'outils tiers. Cela dit, vous devez vous assurer que le séparateur de ligne de votre fichier est correct et que vous lisez le nombre d'octets correct pour le trouver.