Чтение содержимого gzip файла с AWS S3 в Python

Я пытаюсь прочитать некоторые журналы из процесса Hadoop, который я запускаю в AWS. Журналы хранятся в папке S3 и имеют следующий путь.

bucketname = name key = y/z/stderr.gz Здесь Y - это идентификатор кластера, а z - имя папки. Оба они действуют как папки (объекты) в AWS. Таким образом, полный путь похож на x/y/z/stderr.gz.

Теперь я хочу разархивировать этот.gz файл и прочитать содержимое файла. Я не хочу загружать этот файл в мою систему, чтобы сохранить содержимое в переменной python.

Это то, что я пробовал до сих пор.

bucket_name = "name"
key = "y/z/stderr.gz"
obj = s3.Object(bucket_name,key)
n = obj.get()['Body'].read()

Это дает мне формат, который не читается. Я также пробовал

n = obj.get()['Body'].read().decode('utf-8')

который дает ошибку, utf8 'codec не может декодировать байт 0x8b в позиции 1: недопустимый стартовый байт.

Я также пробовал

gzip = StringIO(obj)
gzipfile = gzip.GzipFile(fileobj=gzip)
content = gzipfile.read()

Это возвращает ошибку IOError: не файл gzipped

Не знаете, как декодировать этот.gz файл.

Изменить - найти решение. Необходимо передать n в него и использовать BytesIO

gzip = BytesIO(n)

Ответ 1

@Amit, я пытался сделать то же самое, чтобы протестировать декодирование файла, и получил ваш код для запуска с некоторыми изменениями. Мне просто пришлось удалить функцию def, return и переименовать переменную gzip, так как это имя используется.

import json
import boto3
from io import BytesIO
import gzip

try:
     s3 = boto3.resource('s3')
     key='YOUR_FILE_NAME.gz'
     obj = s3.Object('YOUR_BUCKET_NAME',key)
     n = obj.get()['Body'].read()
     gzipfile = BytesIO(n)
     gzipfile = gzip.GzipFile(fileobj=gzipfile)
     content = gzipfile.read()
     print(content)
except Exception as e:
    print(e)
    raise e

Ответ 2

Вы можете использовать AWS S3 SELECT Object Content для чтения содержимого gzip

S3 Select - это функция Amazon S3, предназначенная для извлечения только тех данных, которые вам нужны, из объекта, что может значительно повысить производительность и снизить стоимость приложений, которым необходим доступ к данным в S3.

Amazon S3 Select работает с объектами, хранящимися в формате Apache Parquet, массивах JSON и сжатии BZIP2 для объектов CSV и JSON.

Ссылка: https://docs.aws.amazon.com/AmazonS3/latest/dev/selecting-content-from-objects.html

from io import StringIO
import boto3
import pandas as pd

bucket = 'my-bucket'
prefix = 'my-prefix'

client = boto3.client('s3')

for object in client.list_objects_v2(Bucket=bucket, Prefix=prefix)['Contents']:
    if object['Size'] <= 0:
        continue

    print(object['Key'])
    r = client.select_object_content(
            Bucket=bucket,
            Key=object['Key'],
            ExpressionType='SQL',
            Expression="select * from s3object",
            InputSerialization = {'CompressionType': 'GZIP', 'JSON': {'Type': 'DOCUMENT'}},
            OutputSerialization = {'CSV': {'QuoteFields': 'ASNEEDED', 'RecordDelimiter': '\n', 'FieldDelimiter': ',', 'QuoteCharacter': '"', 'QuoteEscapeCharacter': '"'}},
        )

    for event in r['Payload']:
        if 'Records' in event:
            records = event['Records']['Payload'].decode('utf-8')
            payloads = (''.join(r for r in records))
            try:
                select_df = pd.read_csv(StringIO(payloads), error_bad_lines=False)
                for row in select_df.iterrows():
                    print(row)
            except Exception as e:
                print(e)

Ответ 3

Прочитать файл расширения Bz2 из aws s3 в python

import json
import boto3
from io import BytesIO
import bz2
try:
    s3 = boto3.resource('s3')
    key='key_name.bz2'
    obj = s3.Object('bucket_name',key)
    nn = obj.get()['Body'].read()
    gzipfile = BytesIO(nn)
    content = bz2.decompress(gzipfile.read())
    content = content.split('\n')
    print len(content)

except Exception as e:
    print(e)

Ответ 4

Точно так же, как то, что мы делаем с переменными, данные могут храниться в байтах в буфере памяти, когда мы используем операции ввода-вывода Io-модулей Byte IO.

Вот пример программы, чтобы продемонстрировать это:

mport io

stream_str = io.BytesIO(b"JournalDev Python: \x00\x01")
print(stream_str.getvalue())

Функция getvalue() принимает значение из буфера в виде строки.

Итак, ответ @Jean-FrançoisFabre правильный, и вы должны использовать

gzip = BytesIO(n)

Для получения дополнительной информации прочтите следующий документ:

https://docs.python.org/3/library/io.html

Ответ 5

Я попробовал ваш выше код, но все еще получаю ниже ошибки

  "errorMessage": "'_io.BytesIO' object has no attribute 'GzipFile'",
"stackTrace": [
"  File \"/var/task/lambda_function.py\", line 20, in lambda_handler\n    raise e\n",
"  File \"/var/task/lambda_function.py\", line 14, in lambda_handler\n    gzipfile = gzip.GzipFile(fileobj=gzip)\n"

ниже мой код, phython = 3.7

import json
import boto3
from io import BytesIO
import gzip

def lambda_handler(event, context):
try:
     s3 = boto3.resource('s3')
     key='test.gz'
     obj = s3.Object('athenaamit',key)
     n = obj.get()['Body'].read()
     #print(n)
     gzip = BytesIO(n)
     gzipfile = gzip.GzipFile(fileobj=gzip)
     content = gzipfile.read()
     print(content)
     return 'dddd'
except Exception as e:
    print(e)
    raise e

Ответ 6

В настоящее время файл можно прочитать как

role = 'role name'
bucket = 'bucket name'
data_key = 'data key'
data_location = 's3://{}/{}'.format(bucket, data_key)
data = pd.read_csv(data_location,compression='gzip', header=0, sep=',', quotechar='"')