0

Как использовать boto для передачи файла из Amazon S3 в Rackspace Cloud Files?

10

Я копирую файл из S3 в Cloudfiles и хочу избежать записи этого файла на диск. В библиотеке Python-Cloudfiles есть вызов object.stream(), который, похоже, подходит под мои нужды, но я не могу найти эквивалентный вызов в boto. Я надеюсь, что смогу сделать что-то наподобие:

shutil.copyfileobj(s3Object.stream(), rsObject.stream())

Возможно ли это с помощью boto (или, возможно, любой другой библиотеки для работы с S3)?

3 ответ(ов)

0

В объекте Key библиотеки boto, который представляет объект в S3, можно использовать итерацию, поэтому вы можете сделать что-то вроде этого:

>>> import boto
>>> c = boto.connect_s3()
>>> bucket = c.lookup('garnaat_pub')
>>> key = bucket.lookup('Scan1.jpg')
>>> for bytes in key:
...   # здесь вы можете записать байты в выходной поток

Либо, как в вашем примере, вы можете сделать так:

>>> shutil.copyfileobj(key, rsObject.stream())

Этот способ позволяет эффективно копировать данные из объекта S3 в другой поток, используя встроенные методы.

0

Вы правы, многие пользователи, видящие этот вопрос, могут искать способ построчного (или с использованием запятой, или другого разделителя) чтения файла из S3 с использованием boto. Вот простой способ это сделать:

def getS3ResultsAsIterator(self, aws_access_info, key, prefix):        
    s3_conn = S3Connection(**aws_access_info)
    bucket_obj = s3_conn.get_bucket(key)
    # Проходим по списку файлов в указанном ключе
    for f in bucket_obj.list(prefix=prefix):
        unfinished_line = ''
        for byte in f:
            byte = unfinished_line + byte
            # Разделяем по нужному разделителю, или используем регулярку с re.split()
            lines = byte.split('\n')
            unfinished_line = lines.pop()  # Сохраняем незавершенную строку
            for line in lines:
                yield line

Ответ @garnaat остается отличным и абсолютно верным. Надеюсь, мой вариант также поможет кому-то!

0

Ваше решение для обертывания потока данных выглядит очень хорошо. Однако, чтобы обеспечить поддержку итерации по объектам, необходимо добавить методы для итерации, такие как __iter__ и __next__. Ваш текущий класс S3ObjectInterator, который наследуется от io.RawIOBase, не содержит этого функционала.

Вот модифицированный вариант вашего кода с добавлением необходимых методов:

import boto3
import io

class S3ObjectIterator(io.RawIOBase):
    def __init__(self, bucket, key):
        """Инициализация с именами ведра и ключа S3"""
        self.s3c = boto3.client('s3')
        self.obj_stream = self.s3c.get_object(Bucket=bucket, Key=key)['Body']
        self.buffer = b''  # Буфер для хранения данных между вызовами
        self.eof = False   # Конец файла

    def read(self, n=-1):
        """Чтение из потока"""
        if self.eof:
            return b''  # Возвращаем пустой байтовый объект, если конец файла
        data = self.obj_stream.read(n)
        if not data:
            self.eof = True  # Устанавливаем флаг конца файла
        return data

    def __iter__(self):
        """Метод для итерирования"""
        return self

    def __next__(self):
        """Возвращает следующую строку из объекта"""
        line = self.read(1024)  # Читаем фиксированный размер данных
        if not line:
            raise StopIteration  # Завершение итерации, если данных больше нет
        return line.decode('utf-8')  # Декодируем байтовую строку в строку

# Пример использования:

obj_stream = S3ObjectIterator(bucket, key)
for line in obj_stream:
    print(line)

Обратите внимание, что в методе __next__ я добавил необходимость декодирования байтов в строку, чтобы вывод был удобен для чтения. Также размер строки при чтении можно указать, чтобы получить данные по частям, что полезно при работе с большими файлами.

Теперь ваш класс позволяет итерироваться по строкам данных, получаемым из объекта S3.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь