Leer un archivo línea por línea desde S3 usando boto?

Tengo un archivo csv en S3 y estoy tratando de leer la línea del encabezado para obtener el tamaño (estos archivos son creados por nuestros usuarios para que puedan ser de casi cualquier tamaño). ¿Hay alguna manera de hacer esto usando boto? Pensé que tal vez podría usar Python BufferedReader, pero no puedo descubrir cómo abrir una secuencia desde una clave S3. Cualquier sugerencia seria genial. ¡Gracias!

Parece que boto tiene una función de read() que puede hacer esto. Aquí hay un código que me funciona:

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

La llamada a read(n) devuelve los siguientes n bytes del objeto.

Por supuesto, esto no devolverá automáticamente “la línea del encabezado”, pero podría llamarlo con un número lo suficientemente grande como para devolver la línea del encabezado al mínimo.

Puede encontrar https://pypi.python.org/pypi/smart_open útil para su tarea.

De la documentación:

 for line in smart_open.smart_open('s3://mybucket/mykey.txt'): print line 

Aquí hay una solución que realmente transmite los datos línea por línea:

 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 

Con boto3 puede acceder a un flujo en bruto y leer línea por línea. Solo tenga en cuenta que Stream Raw es una propiedad privada por alguna razón.

 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... 

Utilizando boto3:

 s3 = boto3.resource('s3') obj = s3.Object(BUCKET, key) for line in obj.get()['Body']._raw_stream: # do something with line 

Si desea leer varios archivos (línea por línea) con un prefijo de grupo específico (es decir, en una “subcarpeta”) puede hacer esto:

 s3 = boto3.resource('s3', aws_access_key_id='', aws_secret_access_key='') bucket = s3.Bucket('') for obj in bucket.objects.filter(Prefix=''): for line in obj.get()['Body'].read().splitlines(): print(line.decode('utf-8')) 

Aquí las líneas son bytes, así que las estoy decodificando; pero si ya son una cadena, puede omitir eso.

La forma más dinámica y económica de leer el archivo es leer cada byte hasta que encuentre el número de líneas que necesita.

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

No necesitará adivinar el tamaño del encabezado si el tamaño del encabezado puede cambiar, no terminará descargando el archivo completo y no necesitará herramientas de terceros. Por supuesto, debe asegurarse de que el límite de línea en su archivo sea correcto y que esté leyendo el número correcto de bytes para encontrarlo.