বোটো 3 থেকে এস 3 বাল্টিতে সাবফোল্ডারগুলির নাম পুনরুদ্ধার করা


94

বোটো 3 ব্যবহার করে, আমি আমার এডাব্লুএস এস 3 বালতি অ্যাক্সেস করতে পারি:

s3 = boto3.resource('s3')
bucket = s3.Bucket('my-bucket-name')

এখন, বালতিতে ফোল্ডার রয়েছে first-level, যার মধ্যে নিজেই টাইমস্ট্যাম্পের নামের বেশ কয়েকটি সাব-ফোল্ডার রয়েছে 1456753904534। আমি করছি এমন অন্য কাজের জন্য এই সাব-ফোল্ডারগুলির নাম জানতে হবে এবং আমি অবাক হয়েছি যে আমার কাছে বোটো 3 আমি পুনরুদ্ধার করতে পারি কিনা।

সুতরাং আমি চেষ্টা করেছি:

objs = bucket.meta.client.list_objects(Bucket='my-bucket-name')

যা একটি অভিধান দেয়, যার কী 'বিষয়বস্তু' আমাকে দ্বিতীয় স্তরের টাইমস্ট্যাম্প ডিরেক্টরিগুলির পরিবর্তে সমস্ত তৃতীয় স্তরের ফাইল দেয়, আসলে আমি জিনিসগুলির তালিকা সহ একটি তালিকা পাই

{u'ETag ':' "etag" ', u'Key': প্রথম স্তর / 1456753904534 / অংশ -00014 ', u'LastModified': ডেটটাইম.ডেটটাইম (2016, 2, 29, 13, 52, 24, tzinfo = tzutc ()),
u'Owner ': owner u'DisplayName': 'মালিক', u'ID ':' id '},
u'Size': আকার, u'StorageClass ':' স্টোরেজক্লাস '}

আপনি দেখতে পাচ্ছেন যে এই ক্ষেত্রে সুনির্দিষ্ট ফাইলগুলি part-00014পুনরুদ্ধার করা হয়েছে, আমি কেবল ডিরেক্টরিটির নামই পেতে চাই। নীতিগতভাবে আমি সমস্ত পাথ থেকে ডিরেক্টরিটির নামটি সরিয়ে ফেলতে পারতাম তবে দ্বিতীয় স্তরটি অর্জনের জন্য তৃতীয় স্তরে সমস্ত কিছু পুনরুদ্ধার করা কুৎসিত এবং ব্যয়বহুল!

আমি এখানে রিপোর্ট করা কিছু চেষ্টা করেছিলাম :

for o in bucket.objects.filter(Delimiter='/'):
    print(o.key)

তবে আমি ফোল্ডারগুলি পছন্দসই স্তরে পাই না।

এই সমস্যা সমাধানের একটি উপায় আছে কি?


সুতরাং আপনি বলছেন যে এটি কাজ করে না? আপনি যখন এটি চালিয়ে যাবেন তখন কি পোস্ট করতে পারবেন?
জর্ডন ফিলিপস

4
@ জর্ডনফিলিপস আমি আপনার পাঠানো সেই লিঙ্কের প্রথম লাইনগুলি চেষ্টা করেছি, যা আমি এখানে আটকানো করেছি, এবং আমি বালতিটির প্রথম স্তরের টেক্সট ফাইলগুলি পাই এবং কোনও ফোল্ডারও পাই না।
মার টিন

@মার টিন আপনি কি কখনও এই সমস্যাটি সমাধান করেছেন? আমি একই ধরণের সমস্যার মুখোমুখি হয়েছি যেখানে প্রতিটি বালতি সাবফোল্ডারটিতে আমার প্রথম উপাদানটির প্রয়োজন।
টেড টেলর অফ লাইফ

4
@ টেডটেলোরফ্লাইফ হ্যাঁ, সমস্ত অবজেক্টগুলি পাওয়া এবং /সাবফোল্ডারগুলি পেয়ে বিভাজন ছাড়া অন্য কোনও উপায় নেই
মার্চ

4
@ মার টিন আমি যেভাবেই করেছি তা হ'ল আউটপুট নেওয়া, এটি একটি পাঠ্য বিন্যাসে ফেলে দেওয়া এবং "/" দ্বারা কমা বিস্মৃত করা এবং তারপরে প্রথম উপাদানটি অনুলিপি করে আটকানো। পোঁদ কি ব্যাথা।
লাইফ টেড টেইলর

উত্তর:


65

এস 3 হ'ল একটি অবজেক্ট স্টোরেজ, এতে আসল ডিরেক্টরি কাঠামো নেই। "/" বরং প্রসাধনী is লোকেরা ডিরেক্টরি কাঠামো রাখতে চায় তার একটি কারণ, কারণ তারা অ্যাপ্লিকেশনটিতে একটি গাছ বজায় / ছাঁটাই / রাখতে পারেন। এস 3 এর জন্য, আপনি যেমন কাঠামোটিকে বাছাইয়ের সূচি বা অনুসন্ধান ট্যাগ হিসাবে বিবেচনা করেন।

এস 3-তে অবৈধভাবে কারসাজি করতে আপনার বোটো3.ক্লিয়েন্ট বা বোটো3.সোর্স প্রয়োজন, যেমন সমস্ত বস্তুর তালিকা তৈরি করতে

import boto3 
s3 = boto3.client("s3")
all_objects = s3.list_objects(Bucket = 'bucket-name') 

http://boto3.readthedocs.org/en/latest/references/services/s3.html#S3.Client.list_objects

আসলে, যদি s3 অবজেক্টের নামটি '/' বিভাজক ব্যবহার করে সংরক্ষণ করা হয়। তালিকা_অবজেক্টগুলির সর্বশেষ সংস্করণ (list_objects_v2) আপনাকে নির্দিষ্ট উপসর্গ দিয়ে শুরু হওয়া কীগুলির প্রতিক্রিয়া সীমাবদ্ধ করতে দেয়।

নির্দিষ্ট সাব-ফোল্ডারগুলির অধীনে আইটেমগুলিকে আইটেমগুলিতে সীমাবদ্ধ করতে:

    import boto3 
    s3 = boto3.client("s3")
    response = s3.list_objects_v2(
            Bucket=BUCKET,
            Prefix ='DIR1/DIR2',
            MaxKeys=100 )

ডকুমেন্টেশন

আরেকটি বিকল্প হ'ল পাইথন os.path ফাংশনটি ফোল্ডার উপসর্গটি বের করতে। সমস্যা হ'ল এটির জন্য অনাকাঙ্ক্ষিত ডিরেক্টরি থেকে তালিকাভুক্ত অবজেক্টের প্রয়োজন হবে।

import os
s3_key = 'first-level/1456753904534/part-00014'
filename = os.path.basename(s3_key) 
foldername = os.path.dirname(s3_key)

# if you are not using conventional delimiter like '#' 
s3_key = 'first-level#1456753904534#part-00014
filename = s3_key.split("#")[-1]

বোটো 3 সম্পর্কে একটি অনুস্মারক: boto3.resource একটি দুর্দান্ত উচ্চ স্তরের এপিআই। বোটো3.প্লিয়েন্ট বনাম বোটো3.সোর্স ব্যবহার করে এমন বিভিন্ন উপকারিতা রয়েছে। আপনি যদি অভ্যন্তরীণ ভাগ করা লাইব্রেরি বিকাশ করেন, বোটো 3. রিসোর্স ব্যবহার করা আপনাকে ব্যবহৃত সংস্থানগুলির উপর একটি ব্ল্যাকবক্স স্তর দেবে।


4
এটি আমার প্রশ্নের একই সাথে আমার একই ফলাফলটি দেয়। আমার ধারণা, ফোল্ডারের নাম পাওয়ার জন্য আমাকে ফিরে আসা অবজেক্টগুলি থেকে সমস্ত কীগুলি ধরে নিয়ে স্ট্রিংটি বিভক্ত করে শক্ত পথটি সমাধান করতে হবে।
মার টিন 12

4
@ মার্টিনা: অলস অজগরটি বিভক্ত হয়ে তালিকার অভ্যন্তরে শেষ তথ্যগুলি ধরুন যেমন ফাইলের নাম = কী নাম.স্প্লিট ("/") [- 1]
মটমূট 16'6

4
@ মার্টিন directory_name = os.path.dirname(directory/path/and/filename.txt)এবংfile_name = os.path.basename(directory/path/and/filename.txt)
জেকেদেব

109

কোডের টুকরো নীচে কেবল এস3 বালতি থেকে 'ফোল্ডারে' কেবল 'সাবফোল্ডার' পাওয়া যায়।

import boto3
bucket = 'my-bucket'
#Make sure you provide / in the end
prefix = 'prefix-name-with-slash/'  

client = boto3.client('s3')
result = client.list_objects(Bucket=bucket, Prefix=prefix, Delimiter='/')
for o in result.get('CommonPrefixes'):
    print 'sub folder : ', o.get('Prefix')

আরও তথ্যের জন্য, আপনি https://github.com/boto/boto3/issues/134 দেখুন


12
আমি যদি কোনও বিশেষ সাবফোল্ডারের বিষয়বস্তু তালিকাবদ্ধ করতে চাই তবে কী হবে?
আজহার 22 কে

4
@ আজহার 22 কে, আমি ধরে নিয়েছি আপনি প্রতিটি 'সাব ফোল্ডার' এর জন্য পুনরাবৃত্তভাবে ফাংশনটি চালাতে পারবেন।
সার্বান সেজার

যদি 1000 টিরও বেশি উপসর্গ থাকে?
Kostrahb

42

সংক্ষিপ্ত উত্তর :

  • ব্যবহার Delimiter='/'। এটি আপনার বালতির একটি পুনরাবৃত্ত তালিকা করা থেকে বিরত থাকে। এখানে কিছু উত্তর ভুলভাবে পুরো তালিকা তৈরি করার এবং ডিরেক্টরিগুলির নামগুলি পুনরুদ্ধার করতে কিছু স্ট্রিং ম্যানিপুলেশন ব্যবহার করার পরামর্শ দেয়। এটি মারাত্মকভাবে অদক্ষ হতে পারে। মনে রাখবেন যে বালতিতে থাকা বস্তুর সংখ্যার উপর এস 3 এর কার্যত কোনও সীমা নেই। সুতরাং, কল্পনা করুন যে এর মধ্যে bar/এবং foo/আপনার কাছে একটি ট্রিলিয়ন বস্তু রয়েছে: আপনি পেতে খুব দীর্ঘ সময় অপেক্ষা করবেন ['bar/', 'foo/']

  • ব্যবহার Paginators। একই কারণে (এস 3 একটি ইঞ্জিনিয়ারের অনন্তের অনুমান), আপনাকে অবশ্যই পৃষ্ঠাগুলির মাধ্যমে তালিকা তৈরি করতে হবে এবং মেমরির সমস্ত তালিকা সঞ্চয় করা এড়াতে হবে। পরিবর্তে, আপনার "লিস্টার "টিকে পুনরুক্তি হিসাবে বিবেচনা করুন এবং এটি উত্পাদিত স্ট্রিমটি পরিচালনা করুন।

  • ব্যবহার boto3.client, না boto3.resourceresourceসংস্করণ ভাল হ্যান্ডেল বলে মনে হচ্ছে না Delimiterবিকল্প। আপনি যদি একটি সংস্থান আছে, তাহলে একটি বলে bucket = boto3.resource('s3').Bucket(name)আপনার সাথে সংশ্লিষ্ট ক্লায়েন্ট পেতে পারেন: bucket.meta.client

দীর্ঘ উত্তর :

নিম্নলিখিতটি একটি পুনরাবৃত্তিকারী যা আমি সাধারণ বালতিগুলির জন্য ব্যবহার করি (কোনও সংস্করণ হ্যান্ডলিং নেই)।

import boto3
from collections import namedtuple
from operator import attrgetter


S3Obj = namedtuple('S3Obj', ['key', 'mtime', 'size', 'ETag'])


def s3list(bucket, path, start=None, end=None, recursive=True, list_dirs=True,
           list_objs=True, limit=None):
    """
    Iterator that lists a bucket's objects under path, (optionally) starting with
    start and ending before end.

    If recursive is False, then list only the "depth=0" items (dirs and objects).

    If recursive is True, then list recursively all objects (no dirs).

    Args:
        bucket:
            a boto3.resource('s3').Bucket().
        path:
            a directory in the bucket.
        start:
            optional: start key, inclusive (may be a relative path under path, or
            absolute in the bucket)
        end:
            optional: stop key, exclusive (may be a relative path under path, or
            absolute in the bucket)
        recursive:
            optional, default True. If True, lists only objects. If False, lists
            only depth 0 "directories" and objects.
        list_dirs:
            optional, default True. Has no effect in recursive listing. On
            non-recursive listing, if False, then directories are omitted.
        list_objs:
            optional, default True. If False, then directories are omitted.
        limit:
            optional. If specified, then lists at most this many items.

    Returns:
        an iterator of S3Obj.

    Examples:
        # set up
        >>> s3 = boto3.resource('s3')
        ... bucket = s3.Bucket(name)

        # iterate through all S3 objects under some dir
        >>> for p in s3ls(bucket, 'some/dir'):
        ...     print(p)

        # iterate through up to 20 S3 objects under some dir, starting with foo_0010
        >>> for p in s3ls(bucket, 'some/dir', limit=20, start='foo_0010'):
        ...     print(p)

        # non-recursive listing under some dir:
        >>> for p in s3ls(bucket, 'some/dir', recursive=False):
        ...     print(p)

        # non-recursive listing under some dir, listing only dirs:
        >>> for p in s3ls(bucket, 'some/dir', recursive=False, list_objs=False):
        ...     print(p)
"""
    kwargs = dict()
    if start is not None:
        if not start.startswith(path):
            start = os.path.join(path, start)
        # note: need to use a string just smaller than start, because
        # the list_object API specifies that start is excluded (the first
        # result is *after* start).
        kwargs.update(Marker=__prev_str(start))
    if end is not None:
        if not end.startswith(path):
            end = os.path.join(path, end)
    if not recursive:
        kwargs.update(Delimiter='/')
        if not path.endswith('/'):
            path += '/'
    kwargs.update(Prefix=path)
    if limit is not None:
        kwargs.update(PaginationConfig={'MaxItems': limit})

    paginator = bucket.meta.client.get_paginator('list_objects')
    for resp in paginator.paginate(Bucket=bucket.name, **kwargs):
        q = []
        if 'CommonPrefixes' in resp and list_dirs:
            q = [S3Obj(f['Prefix'], None, None, None) for f in resp['CommonPrefixes']]
        if 'Contents' in resp and list_objs:
            q += [S3Obj(f['Key'], f['LastModified'], f['Size'], f['ETag']) for f in resp['Contents']]
        # note: even with sorted lists, it is faster to sort(a+b)
        # than heapq.merge(a, b) at least up to 10K elements in each list
        q = sorted(q, key=attrgetter('key'))
        if limit is not None:
            q = q[:limit]
            limit -= len(q)
        for p in q:
            if end is not None and p.key >= end:
                return
            yield p


def __prev_str(s):
    if len(s) == 0:
        return s
    s, c = s[:-1], ord(s[-1])
    if c > 0:
        s += chr(c - 1)
    s += ''.join(['\u7FFF' for _ in range(10)])
    return s

পরীক্ষা :

নিম্নলিখিত আচরণ পরীক্ষা করার জন্য সহায়ক paginatorএবং list_objects। এটি অনেকগুলি ডায়ার এবং ফাইল তৈরি করে। যেহেতু পৃষ্ঠাগুলি 1000 এন্ট্রি পর্যন্ত, আমরা ডায়ার এবং ফাইলগুলির জন্য এর একাধিকটি ব্যবহার করি। dirsকেবলমাত্র ডিরেক্টরি রয়েছে (প্রত্যেকটির একটি করে অবজেক্ট রয়েছে)। mixedপ্রতিটি ডিরের জন্য 2 টি বস্তুর অনুপাত সহ ডায়ার এবং অবজেক্টের সংমিশ্রণ রয়েছে (অবশ্যই ডির অধীনে একটি বস্তু অবশ্যই; এস 3 কেবলমাত্র বস্তু সঞ্চয় করে)।

import concurrent
def genkeys(top='tmp/test', n=2000):
    for k in range(n):
        if k % 100 == 0:
            print(k)
        for name in [
            os.path.join(top, 'dirs', f'{k:04d}_dir', 'foo'),
            os.path.join(top, 'mixed', f'{k:04d}_dir', 'foo'),
            os.path.join(top, 'mixed', f'{k:04d}_foo_a'),
            os.path.join(top, 'mixed', f'{k:04d}_foo_b'),
        ]:
            yield name


with concurrent.futures.ThreadPoolExecutor(max_workers=32) as executor:
    executor.map(lambda name: bucket.put_object(Key=name, Body='hi\n'.encode()), genkeys())

ফলস্বরূপ কাঠামোটি হ'ল:

./dirs/0000_dir/foo
./dirs/0001_dir/foo
./dirs/0002_dir/foo
...
./dirs/1999_dir/foo
./mixed/0000_dir/foo
./mixed/0000_foo_a
./mixed/0000_foo_b
./mixed/0001_dir/foo
./mixed/0001_foo_a
./mixed/0001_foo_b
./mixed/0002_dir/foo
./mixed/0002_foo_a
./mixed/0002_foo_b
...
./mixed/1999_dir/foo
./mixed/1999_foo_a
./mixed/1999_foo_b

এর s3listথেকে প্রাপ্ত প্রতিক্রিয়াগুলি পরীক্ষা করার জন্য উপরে দেওয়া কোডটির কিছুটা চিকিত্সা সহ paginatorআপনি কিছু মজাদার তথ্য পর্যবেক্ষণ করতে পারেন:

  • Markerসত্যিই স্বতন্ত্র। প্রদত্ত Marker=topdir + 'mixed/0500_foo_a'তালিকাটি সেই কী ( আমাজনএস 3 এপিআই অনুসারে ) এর পরে শুরু করবে , যার সাথে । এটাই কারণ ।.../mixed/0500_foo_b__prev_str()

  • Delimiterতালিকাবদ্ধ করার সময় ব্যবহার করে , mixed/প্রতিটি প্রতিক্রিয়াতে paginator666 কী এবং 334 সাধারণ উপসর্গ থাকে। প্রচন্ড প্রতিক্রিয়া না গড়ে এটি বেশ ভাল।

  • বিপরীতে, তালিকাবদ্ধ করার সময় dirs/, এর প্রতিটি প্রতিক্রিয়াতে paginator1000 টি সাধারণ উপসর্গ (এবং কোনও কী নেই) থাকে।

  • সীমাবদ্ধ আকারে PaginationConfig={'MaxItems': limit}সীমা অতিক্রম করা কেবল কীগুলির সংখ্যা, সাধারণ উপসর্গ নয়। আমরা আমাদের পুনরুক্তকারীর স্ট্রিমটি আরও ছাঁটাই করে তা মোকাবিলা করি।


@ মেহেদী: এমন সিস্টেমের পক্ষে এটি এতটা জটিল নয়, যা এমন অবিশ্বাস্য স্কেল এবং বিশ্বাসযোগ্যতা দেয়। যদি আপনি কয়েক শতাধিক টিবি'র বেশি লেনদেন করেন তবে তারা যা দিচ্ছে তার জন্য আপনি প্রশংসা পাবেন। মনে রাখবেন, ড্রাইভে সর্বদা একটি এমটিবিএফ> 0 থাকে ... বড় আকারের ডেটা স্টোরেজটির কী কী প্রভাব রয়েছে সে সম্পর্কে চিন্তা করুন। দাবি অস্বীকার: আমি ২০০ active সাল থেকে পেটাবাইট স্কেল ডেটাতে কাজ করেছি এবং এটি আরও শক্ত হয়ে ওঠে তবে আমি একটি সক্রিয় এবং সুখী এডাব্লুএস ব্যবহারকারী, অন্য কোনও সংযোগ নেই।
পিয়েরে ডি

39

এটি নির্ণয় করতে আমার অনেক সময় লেগেছে, তবে শেষ পর্যন্ত বোটো 3 ব্যবহার করে এস 3 বাল্টিতে সাবফোল্ডারের সামগ্রী তালিকাভুক্ত করার একটি সহজ উপায়। আশা করি এটা সাহায্য করবে

prefix = "folderone/foldertwo/"
s3 = boto3.resource('s3')
bucket = s3.Bucket(name="bucket_name_here")
FilesNotFound = True
for obj in bucket.objects.filter(Prefix=prefix):
     print('{0}:{1}'.format(bucket.name, obj.key))
     FilesNotFound = False
if FilesNotFound:
     print("ALERT", "No file in {0}/{1}".format(bucket, prefix))

4
আপনার ফোল্ডারে যদি প্রচুর পরিমাণে অবজেক্ট থাকে তবে কী হবে?
পিয়েরে ডি

4
আমার বক্তব্যটি এটি একটি মারাত্মকভাবে অদক্ষ সমাধান। এস 3 কীগুলিতে স্বেচ্ছাসেবক বিভাজনকারীদের সাথে ডিল করার জন্য নির্মিত। উদাহরণস্বরূপ '/',। এই যে আপনি "ফোল্ডারগুলি" এগুলিকে পূর্ণরূপে প্যাগিনেট না করে এড়িয়ে যান। এবং তারপরেও, আপনি যদি একটি সম্পূর্ণ তালিকা (যেমন আউস ক্লিমে 'পুনরাবৃত্ত' সমতুল্য) জেদ করেন, তবে আপনাকে অবশ্যই প্যাগিনেটর ব্যবহার করতে হবে বা আপনি কেবল প্রথম 1000 টি বিষয়বস্তু তালিকাভুক্ত করবেন।
পিয়েরে ডি

এটি একটি দুর্দান্ত উত্তর। যাদের এটির প্রয়োজন তাদের জন্য, আমি আমার প্রাপ্ত উত্তরেlimit এটিতে একটি প্রয়োগ করেছি
অ্যাকিউম্যানাস

16

এস 3 এর সাথে বড় উপলব্ধি হ'ল কোনও ফোল্ডার / ডিরেক্টরি নেই কেবল কীগুলি। আপাত ফোল্ডারের গঠন শুধু ফাইলের নাম আগে লেখা হয় 'কী' পরিণত, তাই বিষয়বস্তু তালিকা myBucket's some/path/to/the/file/আপনি চেষ্টা করতে পারেন:

s3 = boto3.client('s3')
for obj in s3.list_objects_v2(Bucket="myBucket", Prefix="some/path/to/the/file/")['Contents']:
    print(obj['Key'])

যা আপনাকে এরকম কিছু দেবে:

some/path/to/the/file/yo.jpg
some/path/to/the/file/meAndYou.gif
...

এটি একটি ভাল উত্তর, তবে এটি কেবলমাত্র 1000 টি অবজেক্ট এবং আরও কিছু পাবেন না। আমি একটি উত্পন্ন উত্তর তৈরি করেছি যা বৃহত সংখ্যক অবজেক্টগুলি পুনরুদ্ধার করতে পারে।
অ্যাকিউম্যানাস

হাঁ, @Acumenus আমি অনুমান আপনার উত্তর বেশি জটিল
CpILL

16

আমারও একই সমস্যা ছিল কিন্তু এটি ব্যবহার সমাধান করতে পরিচালিত boto3.clientএবং list_objects_v2সঙ্গে Bucketএবং StartAfterপ্যারামিটার।

s3client = boto3.client('s3')
bucket = 'my-bucket-name'
startAfter = 'firstlevelFolder/secondLevelFolder'

theobjects = s3client.list_objects_v2(Bucket=bucket, StartAfter=startAfter )
for object in theobjects['Contents']:
    print object['Key']

উপরের কোডটির আউটপুট ফলাফল নিম্নলিখিত প্রদর্শিত হবে:

firstlevelFolder/secondLevelFolder/item1
firstlevelFolder/secondLevelFolder/item2

Boto3 list_objects_v2 ডকুমেন্টেশন

secondLevelFolderআমি কেবল পাইথন পদ্ধতি ব্যবহার করেছি কেবল ডিরেক্টরি নামটি ছড়িয়ে দিতে split():

s3client = boto3.client('s3')
bucket = 'my-bucket-name'
startAfter = 'firstlevelFolder/secondLevelFolder'

theobjects = s3client.list_objects_v2(Bucket=bucket, StartAfter=startAfter )
for object in theobjects['Contents']:
    direcoryName = object['Key'].encode("string_escape").split('/')
    print direcoryName[1]

উপরের কোডটির আউটপুট ফলাফল নিম্নলিখিত প্রদর্শিত হবে:

secondLevelFolder
secondLevelFolder

পাইথন স্প্লিট () ডকুমেন্টেশন

আপনি যদি ডিরেক্টরিটির নাম এবং সামগ্রীর আইটেমের নাম পেতে চান তবে নীচের সাথে মুদ্রণ লাইনটি প্রতিস্থাপন করুন:

print "{}/{}".format(fileName[1], fileName[2])

এবং নিম্নলিখিতটি আউটপুট হবে:

secondLevelFolder/item2
secondLevelFolder/item2

আশাকরি এটা সাহায্য করবে


9

নিম্নলিখিতটি আমার জন্য কাজ করে ... এস 3 বস্তু:

s3://bucket/
    form1/
       section11/
          file111
          file112
       section12/
          file121
    form2/
       section21/
          file211
          file112
       section22/
          file221
          file222
          ...
      ...
   ...

ব্যবহার:

from boto3.session import Session
s3client = session.client('s3')
resp = s3client.list_objects(Bucket=bucket, Prefix='', Delimiter="/")
forms = [x['Prefix'] for x in resp['CommonPrefixes']] 

আমরা পেতে:

form1/
form2/
...

সঙ্গে:

resp = s3client.list_objects(Bucket=bucket, Prefix='form1/', Delimiter="/")
sections = [x['Prefix'] for x in resp['CommonPrefixes']] 

আমরা পেতে:

form1/section11/
form1/section12/

এটি আমার জন্য একমাত্র সমাধান যা কাজ করেছিল কারণ আমার বালতির মূলের "ফোল্ডারগুলি" দরকার ছিল, উপসর্গটি '' "হতে হবে অন্যথায় এটি" / "দিয়ে শেষ করতে হবে
অলিভার

7

আপনি যখন aws s3 ls s3://my-bucket/দৌড়াবেন তখন এডাব্লুএস ক্লিটি এটি করে (সম্ভবত বালতির সমস্ত কী দিয়ে আনা এবং পুনরাবৃত্তি ছাড়াই) , সুতরাং আমি বুঝতে পেরেছিলাম বোটো 3 ব্যবহার করার উপায় থাকতে হবে।

https://github.com/aws/aws-cli/blob/0fedc4c1b6a7aee13e2ed10c3ada778c702c22c3/awscli/customizations/s3/subcommands.py#L499

দেখে মনে হচ্ছে তারা প্রকৃতপক্ষে উপসর্গ এবং ডিলিমিটার ব্যবহার করে - আমি এমন একটি ফাংশন লিখতে সক্ষম হয়েছি যা সেই কোডটি কিছুটা সংশোধন করে আমাকে বালতিটির মূল স্তরে সমস্ত ডিরেক্টরি পেতে পারে:

def list_folders_in_bucket(bucket):
    paginator = boto3.client('s3').get_paginator('list_objects')
    folders = []
    iterator = paginator.paginate(Bucket=bucket, Prefix='', Delimiter='/', PaginationConfig={'PageSize': None})
    for response_data in iterator:
        prefixes = response_data.get('CommonPrefixes', [])
        for prefix in prefixes:
            prefix_name = prefix['Prefix']
            if prefix_name.endswith('/'):
                folders.append(prefix_name.rstrip('/'))
    return folders

2

এখানে একটি সম্ভাব্য সমাধান:

def download_list_s3_folder(my_bucket,my_folder):
    import boto3
    s3 = boto3.client('s3')
    response = s3.list_objects_v2(
        Bucket=my_bucket,
        Prefix=my_folder,
        MaxKeys=1000)
    return [item["Key"] for item in response['Contents']]

2

কেন s3pathপ্যাকেজটি ব্যবহার করবেন না যা এটি কাজ করার মতো সুবিধাজনক করে তুলেছে pathlib? আপনি অবশ্যই ব্যবহার করা উচিতboto3 :

ব্যবহার boto3.resource

এটি zচ্ছিক প্রয়োগের জন্য এটিজ-আজহারের উত্তরের উপর ভিত্তি করে তৈরি করে limitboto3.clientসংস্করণটির তুলনায় এটি স্পষ্টতই ব্যবহার করা সহজ ।

import logging
from typing import List, Optional

import boto3
from boto3_type_annotations.s3 import ObjectSummary  # pip install boto3_type_annotations

log = logging.getLogger(__name__)
_S3_RESOURCE = boto3.resource("s3")

def s3_list(bucket_name: str, prefix: str, *, limit: Optional[int] = None) -> List[ObjectSummary]:
    """Return a list of S3 object summaries."""
    # Ref: https://stackoverflow.com/a/57718002/
    return list(_S3_RESOURCE.Bucket(bucket_name).objects.limit(count=limit).filter(Prefix=prefix))


if __name__ == "__main__":
    s3_list("noaa-gefs-pds", "gefs.20190828/12/pgrb2a", limit=10_000)

ব্যবহার boto3.client

এটি 1000 টিরও বেশি অবজেক্ট পুনরুদ্ধার করার জন্য সিপিলের উত্তরের ব্যবহার করে list_objects_v2এবং তৈরি করে ।

import logging
from typing import cast, List

import boto3

log = logging.getLogger(__name__)
_S3_CLIENT = boto3.client("s3")

def s3_list(bucket_name: str, prefix: str, *, limit: int = cast(int, float("inf"))) -> List[dict]:
    """Return a list of S3 object summaries."""
    # Ref: https://stackoverflow.com/a/57718002/
    contents: List[dict] = []
    continuation_token = None
    if limit <= 0:
        return contents
    while True:
        max_keys = min(1000, limit - len(contents))
        request_kwargs = {"Bucket": bucket_name, "Prefix": prefix, "MaxKeys": max_keys}
        if continuation_token:
            log.info(  # type: ignore
                "Listing %s objects in s3://%s/%s using continuation token ending with %s with %s objects listed thus far.",
                max_keys, bucket_name, prefix, continuation_token[-6:], len(contents))  # pylint: disable=unsubscriptable-object
            response = _S3_CLIENT.list_objects_v2(**request_kwargs, ContinuationToken=continuation_token)
        else:
            log.info("Listing %s objects in s3://%s/%s with %s objects listed thus far.", max_keys, bucket_name, prefix, len(contents))
            response = _S3_CLIENT.list_objects_v2(**request_kwargs)
        assert response["ResponseMetadata"]["HTTPStatusCode"] == 200
        contents.extend(response["Contents"])
        is_truncated = response["IsTruncated"]
        if (not is_truncated) or (len(contents) >= limit):
            break
        continuation_token = response["NextContinuationToken"]
    assert len(contents) <= limit
    log.info("Returning %s objects from s3://%s/%s.", len(contents), bucket_name, prefix)
    return contents


if __name__ == "__main__":
    s3_list("noaa-gefs-pds", "gefs.20190828/12/pgrb2a", limit=10_000)

0

প্রথমত, এস 3-তে কোনও আসল ফোল্ডার ধারণা নেই। আপনার কাছে অবশ্যই একটি ফাইল থাকতে পারে @'/folder/subfolder/myfile.txt' এবং কোনও ফোল্ডার বা সাবফোল্ডারও থাকতে পারে।

এস 3-তে একটি ফোল্ডার "অনুকরণ" করতে, আপনাকে অবশ্যই তার নামের শেষে '/' দিয়ে একটি ফাঁকা ফাইল তৈরি করতে হবে (দেখুন অ্যামাজন এস 3 বোটো দেখুন - ফোল্ডারটি কীভাবে তৈরি করবেন? )

আপনার সমস্যার জন্য, আপনার সম্ভবত get_all_keysপ্যারামিটারগুলির সাথে পদ্ধতিটি ব্যবহার করা উচিত :prefix এবংdelimiter

https://github.com/boto/boto/blob/develop/boto/s3/bucket.py#L427

for key in bucket.get_all_keys(prefix='first-level/', delimiter='/'):
    print(key.name)

4
আমি ভয় করি আমার কাছে বালতি অবজেক্টে get_all_keys পদ্ধতি নেই। আমি বোটো 3 সংস্করণটি 1.2.3 ব্যবহার করছি।
মার টিন

সবেমাত্র বোটো 1.2a টি পরীক্ষা করা হয়েছে: সেখানে বালতির একটি পদ্ধতি listরয়েছে prefixএবং রয়েছে delimiter। আমি মনে করি এটি কাজ করা উচিত।
পিরহেয়াস

4
প্রশ্নটিতে পোস্ট করার সাথে সাথে বালতি অবজেক্টটি পুনরুদ্ধার করা হয়েছে those পদ্ধতিগুলি নেই। আমি বোটো 3 1.2 এ আছি, আপনার লিঙ্কটি কোন সংস্করণটি উল্লেখ করে?
মার টিন


0

আমি জানি যে বোটো 3 বিষয়টি এখানে আলোচিত হচ্ছে, তবে আমি দেখতে পেলাম যে কেবলমাত্র এসএসসিআই ব্যবহার করা এটি আরও দ্রুত এবং আরও স্বজ্ঞাত মতো জন্য - অ্যাডসকলি আরও বেশি ক্ষমতা বজায় রাখে যা বোটো 3 এর চেয়ে উপযুক্ত।

উদাহরণস্বরূপ, যদি আমার প্রদত্ত বালতির সাথে সম্পর্কিত "সাবফোল্ডারগুলি" তে অবজেক্টস সংরক্ষিত থাকে তবে আমি সেগুলি এই জাতীয় কিছু দিয়ে তালিকাভুক্ত করতে পারি:

1) 'মাইডাটা' = বালতির নাম

2) 'f1 / f2 / f3' = "পথ" "ফাইল" বা নেতৃত্ব দেয় বস্তুর দিকে নিয়ে যায়

3) 'foo2.csv, barfar.segy, gar.tar' = সমস্ত বস্তু "ভিতরে" f3

সুতরাং, আমরা এই অবজেক্টগুলির দিকে পরিচালিত "পরম পথ" সম্পর্কে ভাবতে পারি: 'মায়াডাটা / এফ 1 / এফ 2 / এফ 3 / foo2.csv' ...

Awscli কমান্ড ব্যবহার করে, আমরা সহজেই প্রদত্ত "সাবফোল্ডার" এর মধ্যে সমস্ত অবজেক্টের মাধ্যমে তালিকা তৈরি করতে পারি:

এউএস এস 3 এলএস এস 3: // মাইডাটা / এফ 1 / এফ 2 / এফ 3 / - রিসার্চ


0

নীচে কোডের টুকরোটি যা পৃষ্ঠাগুলি পরিচালনা করতে পারে যদি আপনি প্রচুর সংখ্যক এস 3 বালতি অবজেক্ট আনার চেষ্টা করছেন:

def get_matching_s3_objects(bucket, prefix="", suffix=""):

    s3 = boto3.client("s3")
    paginator = s3.get_paginator("list_objects_v2")

    kwargs = {'Bucket': bucket}

    # We can pass the prefix directly to the S3 API.  If the user has passed
    # a tuple or list of prefixes, we go through them one by one.
    if isinstance(prefix, str):
        prefixes = (prefix, )
    else:
        prefixes = prefix

    for key_prefix in prefixes:
        kwargs["Prefix"] = key_prefix

        for page in paginator.paginate(**kwargs):
            try:
                contents = page["Contents"]
            except KeyError:
                return

            for obj in contents:
                key = obj["Key"]
                if key.endswith(suffix):
                    yield obj

প্রথম পৃষ্ঠাটি যদি "কমনপ্রিফিক্সস" পূর্ণ হয় এবং কোনও "বিষয়বস্তু" কী সরবরাহ করে না তবে কী হবে। আমি মনে করি, সঠিক প্রয়োগটি অনুপস্থিত বিষয়বস্তু কীগুলি এড়িয়ে যাবে এবং পরবর্তী পৃষ্ঠায় চালিয়ে যাবে।
জান ভি্লকিনস্কি

0

বোটো ১.১৩.৩ হিসাবে এটি এতটা সহজ হয়ে যায় (যদি আপনি সমস্ত পৃষ্ঠা সংক্রান্ত বিবেচনা বাদ দেন, যা অন্যান্য উত্তরে অন্তর্ভুক্ত ছিল):

def get_sub_paths(bucket, prefix):
s3 = boto3.client('s3')
response = s3.list_objects_v2(
    Bucket=bucket,
    Prefix=prefix,
    MaxKeys=1000)
return [item["Prefix"] for item in response['CommonPrefixes']]
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.