Как сохранить объект S3 в файл с помощью boto3
Я пытаюсь сделать "Привет мир" с новыми boto3 клиент для AWS.
вариант использования у меня довольно простой: получить объект из S3 и сохранить его в файл.
В boto 2.X я бы сделал это так:
import boto
key = boto.connect_s3().get_bucket('foo').get_key('foo')
key.get_contents_to_filename('/tmp/foo')
В boto 3 . Я не могу найти чистый способ сделать то же самое, поэтому я вручную повторяю объект" Streaming":
import boto3
key = boto3.resource('s3').Object('fooo', 'docker/my-image.tar.gz').get()
with open('/tmp/my-image.tar.gz', 'w') as f:
chunk = key['Body'].read(1024*8)
while chunk:
f.write(chunk)
chunk = key['Body'].read(1024*8)
или
import boto3
key = boto3.resource('s3').Object('fooo', 'docker/my-image.tar.gz').get()
with open('/tmp/my-image.tar.gz', 'w') as f:
for chunk in iter(lambda: key['Body'].read(4096), b''):
f.write(chunk)
и он отлично работает. Мне было интересно, есть ли "родная" функция boto3, которая будет выполнять ту же задачу?
6 ответов:
есть настройка, которая недавно вошла в Boto3, которая помогает в этом (среди прочего). В настоящее время он открыт на низкоуровневом клиенте S3 и может использоваться следующим образом:
s3_client = boto3.client('s3') open('hello.txt').write('Hello, world!') # Upload the file to S3 s3_client.upload_file('hello.txt', 'MyBucket', 'hello-remote.txt') # Download the file from S3 s3_client.download_file('MyBucket', 'hello-remote.txt', 'hello2.txt') print(open('hello2.txt').read())
эти функции будут автоматически обрабатывать чтение / запись файлов, а также выполнять параллельную загрузку нескольких частей для больших файлов.
boto3 теперь имеет более приятный интерфейс, чем клиент:
resource = boto3.resource('s3') my_bucket = resource.Bucket('MyBucket') my_bucket.download_file(key, local_filename)
Это само по себе не намного лучше, чем
client
в принятом ответе (хотя документы говорят, что он лучше выполняет повторную попытку загрузки и загрузки при сбое), но учитывая, что ресурсы, как правило, более эргономичны (например, s3 ведра и объект ресурсы лучше, чем методы клиента) это позволяет вам оставаться на уровне ресурсов без приходится падать вниз.
Resources
как правило, может быть создан таким же образом, как и клиенты, и они берут все или большинство тех же аргументов и просто передают их своим внутренним клиентам.
для тех из вас, кто хотел бы сымитировать
set_contents_from_string
как методы boto2, вы можете попробоватьimport boto3 from cStringIO import StringIO s3c = boto3.client('s3') contents = 'My string to save to S3 object' target_bucket = 'hello-world.by.vor' target_file = 'data/hello.txt' fake_handle = StringIO(contents) # notice if you do fake_handle.read() it reads like a file handle s3c.put_object(Bucket=target_bucket, Key=target_file, Body=fake_handle.read())
Для Python3:
в python3 оба StringIO и cStringIO ушли. Используйте
StringIO
импорт так:from io import StringIO
для поддержки обеих версий:
try: from StringIO import StringIO except ImportError: from io import StringIO
# Preface: File is json with contents: {'name': 'Android', 'status': 'ERROR'} import boto3 import io s3 = boto3.resource( 's3', aws_access_key_id='my_access_id', aws_secret_access_key='my_secret_key' ) obj = s3.Object('my-bucket', 'key-to-file.json') data = io.BytesIO() obj.download_fileobj(data) # object is now a bytes string, Converting it to a dict: new_dict = json.loads(data.getvalue().decode("utf-8")) print(new_dict['status']) # Should print "Error"
примечание: Я предполагаю, что вы настроили проверку подлинности отдельно. Ниже приведен код для загрузки одного объекта из корзины S3.
import boto3 #initiate s3 client s3 = boto3.resource('s3') #Download object to the file s3.Bucket('mybucket').download_file('hello.txt', '/tmp/hello.txt')
Если вы хотите прочитать файл с другой конфигурацией, чем по умолчанию, не стесняйтесь использовать либо
mpu.aws.s3_download(s3path, destination)
непосредственно или скопированный код:def s3_download(source, destination, exists_strategy='raise', profile_name=None): """ Copy a file from an S3 source to a local destination. Parameters ---------- source : str Path starting with s3://, e.g. 's3://bucket-name/key/foo.bar' destination : str exists_strategy : {'raise', 'replace', 'abort'} What is done when the destination already exists? profile_name : str, optional AWS profile Raises ------ botocore.exceptions.NoCredentialsError Botocore is not able to find your credentials. Either specify profile_name or add the environment variables AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN. See https://boto3.readthedocs.io/en/latest/guide/configuration.html """ exists_strategies = ['raise', 'replace', 'abort'] if exists_strategy not in exists_strategies: raise ValueError('exists_strategy \'{}\' is not in {}' .format(exists_strategy, exists_strategies)) session = boto3.Session(profile_name=profile_name) s3 = session.resource('s3') bucket_name, key = _s3_path_split(source) if os.path.isfile(destination): if exists_strategy is 'raise': raise RuntimeError('File \'{}\' already exists.' .format(destination)) elif exists_strategy is 'abort': return s3.Bucket(bucket_name).download_file(key, destination)