B33 का उपयोग करके किसी फ़ाइल में S3 ऑब्जेक्ट को कैसे बचाया जाए


132

मैं AWS के लिए नए boto3 क्लाइंट के साथ "हैलो वर्ल्ड" करने की कोशिश कर रहा हूं ।

मेरे पास उपयोग-मामला काफी सरल है: S3 से ऑब्जेक्ट प्राप्त करें और इसे फ़ाइल में सहेजें।

बोटो में 2.XI इसे इस तरह करेगा:

import boto
key = boto.connect_s3().get_bucket('foo').get_key('foo')
key.get_contents_to_filename('/tmp/foo')

बोटो 3 में। मुझे एक ही काम करने का एक साफ तरीका नहीं मिल रहा है, इसलिए मैं "स्ट्रीमिंग" ऑब्जेक्ट पर मैन्युअल रूप से पुनरावृत्ति कर रहा हूं:

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 फ़ंक्शन है जो समान कार्य करेगा?

जवाबों:


216

एक कस्टमाइज़ेशन है जो हाल ही में 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())

ये फ़ंक्शन स्वचालित रूप से फ़ाइलों को पढ़ने / लिखने के साथ-साथ बड़ी फ़ाइलों के लिए समानांतर में मल्टीपार्ट अपलोड करने का काम भी संभालेंगे।

ध्यान दें कि s3_client.download_fileनिर्देशिका नहीं बनेगी। इसे बनाया जा सकता है pathlib.Path('/path/to/file.txt').parent.mkdir(parents=True, exist_ok=True)


1
@ डैनियल: आपके उत्तर के लिए धन्यवाद। यदि आप boto3 में मल्टीपार्ट अपलोड का उपयोग करके फ़ाइल अपलोड करना चाहते हैं तो क्या आप इसका उत्तर दे सकते हैं।
राहुल केपी

1
@RahulKumarPatle upload_fileविधि बड़ी फ़ाइलों के लिए स्वचालित रूप से मल्टीपार्ट अपलोड का उपयोग करेगी।
डैनियल

4
इस दृष्टिकोण का उपयोग करके आप कैसे क्रेडेंशियल पास करते हैं?
21

1
@JHIX आप या तो विश्व स्तर पर क्रेडेंशियल्स कॉन्फ़िगर कर सकते हैं (जैसे कि boto3.readthedocs.org/en/latest/guide/… ) देखें या आप क्लाइंट बनाते समय उन्हें पास कर सकते हैं। उपलब्ध विकल्पों पर अधिक जानकारी के लिए boto3.readthedocs.org/en/latest/reference/core/… देखें !
डैनियल

2
@VladNikiporoff "स्रोत से गंतव्य पर अपलोड करें" "स्रोत से गंतव्य तक डाउनलोड करें"
jkdev

59

boto3 में अब क्लाइंट की तुलना में एक अच्छा इंटरफ़ेस है:

resource = boto3.resource('s3')
my_bucket = resource.Bucket('MyBucket')
my_bucket.download_file(key, local_filename)

यह स्वयं clientस्वीकार किए गए उत्तर की तुलना में जबरदस्त रूप से बेहतर नहीं है (हालांकि डॉक्स का कहना है कि यह अपलोड और असफलता पर डाउनलोड को पुनः प्राप्त करने का एक बेहतर काम करता है) लेकिन यह देखते हुए कि संसाधन आमतौर पर अधिक एर्गोनोमिक हैं (उदाहरण के लिए, s3 बाल्टी और ऑब्जेक्ट संसाधन क्लाइंट विधियों की तुलना में अच्छे हैं) यह आपको नीचे गिरने के बिना संसाधन परत पर रहने की अनुमति देता है।

Resources आम तौर पर ग्राहकों के रूप में उसी तरह से बनाया जा सकता है, और वे सभी या अधिकांश एक ही तर्क लेते हैं और बस उन्हें अपने आंतरिक ग्राहकों के लिए अग्रेषित करते हैं।


1
महान उदाहरण, और जोड़ने के लिए चूंकि मूल प्रश्न किसी ऑब्जेक्ट को सहेजने के बारे में पूछता है, यहां प्रासंगिक विधि है my_bucket.upload_file()(या my_bucket.upload_fileobj()यदि आपके पास एक बाइट्सआईओएस है)।
SMX

वास्तव में, जहां डॉक्स कहते हैं कि resourceपुनः प्रयास करने पर बेहतर काम होता है? मुझे ऐसा कोई संकेत नहीं मिला।
एक्यूमेनस

42

आप में से जो इस 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())

पायथन 3 के लिए:

Python3 में StringIO और cStringIO दोनों गए हैंStringIOआयात का उपयोग करें जैसे:

from io import StringIO

दोनों संस्करण का समर्थन करने के लिए:

try:
   from StringIO import StringIO
except ImportError:
   from io import StringIO

15
यही जवाब है। यहाँ सवाल है: "आप कैसे एक S3 ऑब्जेक्ट को boto3 का उपयोग करके एक स्ट्रिंग को बचाते हैं?"
jkdev

python3 के लिए मुझे आयात io का उपयोग करना पड़ा; fake_handl e = io.StringIO (सामग्री)
फेलिक्स

16
# Preface: File is json with contents: {'name': 'Android', 'status': 'ERROR'}

import boto3
import io

s3 = boto3.resource('s3')

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"

14
कभी भी अपने कोड में अपने AWS_ACCESS_KEY_ID या अपने AWS_SECRET_ACCESS_KEY को न डालें। इन्हें akscli aws configureकमांड से परिभाषित किया जाना चाहिए और ये अपने आप मिल जाएंगे botocore
मील्स एरिकसन

3

जब आप डिफ़ॉल्ट से एक अलग कॉन्फ़िगरेशन वाली फ़ाइल पढ़ना चाहते हैं, तो 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)

from collections import namedtuple

S3Path = namedtuple("S3Path", ["bucket_name", "key"])


def _s3_path_split(s3_path):
    """
    Split an S3 path into bucket and key.

    Parameters
    ----------
    s3_path : str

    Returns
    -------
    splitted : (str, str)
        (bucket, key)

    Examples
    --------
    >>> _s3_path_split('s3://my-bucket/foo/bar.jpg')
    S3Path(bucket_name='my-bucket', key='foo/bar.jpg')
    """
    if not s3_path.startswith("s3://"):
        raise ValueError(
            "s3_path is expected to start with 's3://', " "but was {}"
            .format(s3_path)
        )
    bucket_key = s3_path[len("s3://"):]
    bucket_name, key = bucket_key.split("/", 1)
    return S3Path(bucket_name, key)

काम नहीं करता है। NameError: name '_s3_path_split' is not defined
डेव लियू

@DaveLiu संकेत के लिए धन्यवाद; मैंने कोड समायोजित कर लिया है। पैकेज को पहले काम करना चाहिए था, हालांकि।
मार्टिन थोमा

1

नोट: मैं मान रहा हूं कि आपने प्रमाणीकरण अलग से कॉन्फ़िगर किया है। नीचे कोड 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')
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.