【问题标题】:How to get a list of all distinct prefixes in S3 bucket?如何获取 S3 存储桶中所有不同前缀的列表?
【发布时间】:2021-02-22 21:07:21
【问题描述】:

如果我的目录结构如下,前缀是/folder1,

/folder1/folder11/folder12/folder13/*.files
               /folder21/folder22/folder23/*.files
               /folder31/folder32/*.files

我想动态循环遍历这些目录,以便分别读取每个叶子文件夹中的文件,即我需要一个列表

[
 /folder1/folder11/folder12/folder13/, 
 /folder1/folder21/folder22/folder23/,
 /folder1/folder31/folder32/
]

除了递归遍历每个前缀、获取下一级前缀、连接、获取下一级等,还有更好的方法来获取它,直到到达最后一个(叶)文件夹?

【问题讨论】:

  • 格式化有点误导,/folder1很常见,其余都是子文件夹:/folder1/folder11/folder12/folder13/*.files; /folder1/folder21/folder22/folder23/*.files; /folder1 /folder31/folder32/*.files
  • 循环是你做的方式。或者,可以在开始迭代之前获取 S3 清单以识别感兴趣的前缀。
  • S3 存储是“平面”的,这意味着没有实际的目录结构。所以正如你所说,你最好的选择是为每个前缀做一个 BFS。

标签: python amazon-web-services amazon-s3 boto3 python-s3fs


【解决方案1】:

在列出来自 Amazon S3 的对象时,如果您指定 Delimiter='/',那么它将返回 CommonPrefixes 的列表。这实际上是给定Prefix 的子目录列表。

但是,我建议您不要考虑目录。相反,只需遍历 所有 个对象并查看 Key 即可知道该对象的路径。

如果您只想要包含文件的路径列表,请使用:

import boto3

BUCKET = 'my-bucket'

s3_resource = boto3.resource('s3')
folders = set()

# Find paths of all non-empty objects (to exclude zero-length 'folder' objects)
for object in s3_resource.Bucket(BUCKET).objects.all():
    if object.size > 0 and '/' in object.key:
        folders.add(object.key[:object.key.rfind('/')])

print (folders)

【讨论】:

  • 谢谢,这肯定行得通。在一个不相关的实用程序中,我实际上确实获取了所有对象键并将它们存储在一个集合中以缩减为唯一值。我只是在想,如果每个“叶子文件夹”中有很多文件,它可能会变得异常缓慢。感谢您提供代码示例,将使用它!
【解决方案2】:

您可以在循环中使用它来获取前缀

def get_list_of_prefixes_from_prefix(bucket, prefix):
    """gets list of prefixes for given bucket and prefix"""
    list_of_prefixes = []
    paginator = boto3.resource('s3').meta.client.get_paginator('list_objects')
    for result in paginator.paginate(Bucket=bucket, Prefix=prefix, Delimiter='/'):
        # print(result)
        if 'CommonPrefixes' in result:
            prefixes = [f['Prefix'] for f in result['CommonPrefixes']]
            list_of_prefixes.extend(prefixes)
    return list_of_prefixes

list_of_prefixes = get_list_of_prefixes_from_prefix('my-bucket', 'my-prefix/')

【讨论】:

  • 是的,当我提到在循环中使用它时可能不清楚。捕获 list_of_prefixes 中的前缀,然后在该列表上进行迭代,等等。我没有用例,所以 1 级对我来说没问题。
【解决方案3】:

生成S3 inventory report 并使用 Athena 处理数据。报告的 Athena 表结构也在同一篇 AWS 文章中提到。这是做同样事情的无服务器方法。

【讨论】:

  • 谢谢,会研究
【解决方案4】:
import boto3

list_of_prefixes = []

def get_list_of_prefixes(bucket, prefix):
    global list_of_prefixes
    paginator = boto3.resource('s3').meta.client.get_paginator('list_objects')
    for result in paginator.paginate(Bucket=bucket, Prefix=prefix, Delimiter='/'):
        if 'CommonPrefixes' in result:
            for f in result['CommonPrefixes']:
                get_list_of_prefixes(bucket, f['Prefix'])
        else:
            list_of_prefixes.append(prefix)
    return list_of_prefixes

list_of_prefixes = get_list_of_prefixes('my-bucket', 'my-prefix/')

for i in list_of_prefixes:
    print(i)

【讨论】:

  • 这是一种收集前缀的递归方式,无需为单个对象删除重复键。欢迎批评,我是 Python 和 boto3 的新手。
  • 经过测试,这种递归方案其实比拉取所有对象和砍掉文件名要慢。
猜你喜欢
  • 2016-07-02
  • 2021-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-05
  • 2016-02-06
相关资源
最近更新 更多