如何仅列出特定层级的S3文件夹。

12 浏览
0 Comments

如何仅列出特定层级的S3文件夹。

使用boto3,我可以访问我的AWS S3存储桶:\n

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

\n现在,存储桶中包含文件夹first-level,它本身包含多个以时间戳命名的子文件夹,例如1456753904534。\n为了另一个工作,我需要知道这些子文件夹的名称,我想知道是否可以让boto3为我检索它们。\n所以我尝试了以下代码:\n

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

\n这会返回一个字典,其中键\'Contents\'给出了所有的第三级文件,而不是第二级的时间戳目录,实际上我得到了一个包含如下内容的列表:\n

\n{u\'ETag\': \'\"etag\"\', u\'Key\': first-level/1456753904534/part-00014\', u\'LastModified\':\n datetime.datetime(2016, 2, 29, 13, 52, 24, tzinfo=tzutc()),
\n u\'Owner\': {u\'DisplayName\': \'owner\', u\'ID\':\n \'id\'},
\n u\'Size\': size, u\'StorageClass\': \'storageclass\'}\n

\n你可以看到,这个特定的文件,本例中为part-00014被检索出来,而我只想获得目录的名称。\n原则上,我可以从所有路径中剥离出目录名称,但这样做很丑陋,而且获取第三级的所有内容来获取第二级的内容是很费时费力的!\n我还尝试了这里提到的一些方法:\n

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

\n但我没有得到所需级别的文件夹。\n有没有办法解决这个问题?

0
0 Comments

问题出现的原因是用户想要列出S3存储桶中特定层级的文件夹,但是没有找到合适的方法。解决方法是使用Delimiter参数来避免对存储桶进行递归列举,同时使用Paginators来处理大量的列表,并且使用boto3.client而不是boto3.resource来处理Delimiter选项。下面是详细的解决方法:

1. 使用Delimiter参数来避免递归列举存储桶。设置Delimiter='/'可以只列举出特定层级的文件夹,而不会列举出子文件夹。这样可以避免效率低下的全面列举和字符串操作。示例代码如下:

bucket.meta.client.list_objects(Bucket=bucket.name, Delimiter='/')

2. 使用Paginators来处理大量的列表。由于S3存储桶可以包含大量的对象,必须通过分页来处理列表,并避免将所有列表存储在内存中。可以将列举操作视为一个迭代器,并处理它生成的流。示例代码如下:

paginator = bucket.meta.client.get_paginator('list_objects')
for resp in paginator.paginate(Bucket=bucket.name, Delimiter='/'):
    # 处理每一页的结果
    ...

3. 使用boto3.client而不是boto3.resource来处理Delimiter选项。根据经验,boto3.resource对Delimiter选项的处理不够稳定,因此建议使用boto3.client并使用bucket.meta.client来获取对应的client。示例代码如下:

bucket = boto3.resource('s3').Bucket(name)
client = bucket.meta.client

通过上述方法,用户可以根据特定层级列出S3存储桶中的文件夹。这些方法在处理大量列表和避免递归列举时非常有效。同时,使用boto3.client可以更好地处理Delimiter选项。

0
0 Comments

S3是一种对象存储,它没有真正的目录结构,斜杠“/”只是一种装饰性的符号。人们之所以希望有目录结构,是因为他们可以在应用程序中维护/修剪/添加树。对于S3来说,你可以将这样的结构视为索引或搜索标签。

为了操作S3中的对象,你需要使用boto3.client或boto3.resource。例如,要列出所有对象:

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

实际上,如果S3对象名称使用“/”分隔符存储,那么更新的list_objects(list_objects_v2)版本允许你限制响应为以指定前缀开头的键。

要将项目限制为某些子文件夹中的项目:

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

另一种选择是使用python的os.path函数提取文件夹前缀。问题是,这将需要从不需要的目录中列出对象。

import os
s3_key = 'first-level/1456753904534/part-00014'
filename = os.path.basename(s3_key) 
foldername = os.path.dirname(s3_key)
# 如果你没有使用常规分隔符如"#"
s3_key = 'first-level#1456753904534#part-00014'
filename = s3_key.split("#")[-1]

关于boto3的一个提醒:boto3.resource是一个很好的高级API。使用boto3.client与boto3.resource存在利弊。如果你开发内部共享库,使用boto3.resource将为你提供一层对所使用资源的黑盒封装。

我得到的结果与我在问题中的尝试相同。我想我将不得不通过获取返回对象中的所有键并拆分字符串来解决这个问题,以获取文件夹名称。

:使用惰性python拆分并从列表中选择最后一个数据,例如:filename = keyname.split("/")[-1]

`directory_name = os.path.dirname(directory/path/and/filename.txt)`和`file_name = os.path.basename(directory/path/and/filename.txt)`

严谨地说,"真正的目录结构"是什么意思并不清楚。S3的目录抽象比典型的文件系统更薄,但它们只是抽象,对于这里的目的,在功能上是相同的。

真的想要使用`os.path`工具来操作存储桶键吗?我在寻找一种合法的方法来编辑S3存储桶路径时找到了这个问题,正好是为了避免自己编写路径拼接和/或使用`os.path`,这在Linux上可能可以工作,但在Windows上似乎肯定会失败,并且在概念上“是错误的”。

对于包含许多对象的存储桶,`all_objects = s3.list_objects(Bucket = 'bucket-name')`并不会检索所有对象。

0
0 Comments

问题的出现原因是需要从S3存储桶中列出特定级别的子文件夹,但下面的代码只能返回子文件夹而无法列出子文件夹中的内容。解决方法是在代码中使用递归函数来列出每个子文件夹的内容。如果有超过1000个不同的前缀,可以使用S3的分页功能来处理。

以下是解决该问题的代码示例:

import boto3
def list_s3_folders(bucket, prefix):
    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')
        
        # List contents of sub folder recursively
        list_s3_folders(bucket, o.get('Prefix'))
        
    # Handle pagination if there are more than 1000 prefixes
    if 'NextContinuationToken' in result:
        result = client.list_objects(Bucket=bucket, Prefix=prefix, Delimiter='/', ContinuationToken=result['NextContinuationToken'])
        for o in result.get('CommonPrefixes'):
            print 'sub folder:', o.get('Prefix')
            
            # List contents of sub folder recursively
            list_s3_folders(bucket, o.get('Prefix'))
# Usage
bucket = 'my-bucket'
prefix = 'prefix-name-with-slash/'
list_s3_folders(bucket, prefix)

更多详情请参考:https://github.com/boto/boto3/issues/134

0