Как использовать boto для передачи файла из Amazon S3 в Rackspace Cloud Files?
Я копирую файл из S3 в Cloudfiles и хочу избежать записи этого файла на диск. В библиотеке Python-Cloudfiles есть вызов object.stream(), который, похоже, подходит под мои нужды, но я не могу найти эквивалентный вызов в boto. Я надеюсь, что смогу сделать что-то наподобие:
shutil.copyfileobj(s3Object.stream(), rsObject.stream())
Возможно ли это с помощью boto (или, возможно, любой другой библиотеки для работы с S3)?
3 ответ(ов)
В объекте 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 в другой поток, используя встроенные методы.
Вы правы, многие пользователи, видящие этот вопрос, могут искать способ построчного (или с использованием запятой, или другого разделителя) чтения файла из 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 остается отличным и абсолютно верным. Надеюсь, мой вариант также поможет кому-то!
Ваше решение для обертывания потока данных выглядит очень хорошо. Однако, чтобы обеспечить поддержку итерации по объектам, необходимо добавить методы для итерации, такие как __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.
Как изменить порядок столбцов в DataFrame?
'pip' не распознан как командa внутреннего или внешнего формата
Почему statistics.mean() работает так медленно?
Преобразование строки даты JSON в datetime в Python
Есть ли разница между поднятием экземпляра класса Exception и самого класса Exception?