如何获取子项以进行迭代并最终在AWS S3中迭代其中的文件

时间:2019-06-19 21:20:07

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

我的AWS S3密钥路径为bucket-name/fo1/fo2/fo3,其子路径为 bucket-name/fo1/fo2/fo3/fo_1, bucket-name/fo1/fo2/fo3/fo_2, bucket-name/fo1/fo2/fo3/fo_3,依此类推。我想遍历路径fo_1, fo_2, fo_3 etc.中的这些键bucket-name/fo1/fo2/fo3

我尝试了以下操作,但这不起作用。

s3 = boto3.client('s3')
s3_bucket = 'bucket-name'

prefix = 'fo1/fo2/fo3'
for obj in s3.list_objects_v2(Bucket=s3_bucket, Prefix=prefix, Delimiter='/'):
     # Here when I print obj, it's a string with value as 'MaxKeys'

任何帮助将不胜感激!

更新:

s3://bucket-name/
        fo1/
           fo2/
              fo3/
                 fo_1/
                     file1
                     ...
                 fo_2/
                     file2
                     ...
                 fo_3/
                     file1
                     ...
                 fo_4/
                     file1
                     ...
                 ...

这是我的结构,我希望在其中获取fo_1,fo_2,fo_3和文件。我想要对象fo3中的所有内容,而不要包含其他内容。

3 个答案:

答案 0 :(得分:2)

关于Amazon S3的第一件事是folders do not exist。相反,对象以其完整路径存储为Key(文件名)。

例如,我可以使用AWS Command-Line Interface (CLI)将文件复制到存储桶:

aws s3 cp foo.txt s3://my-bucket/fo1/fo2/fo3/foo.txt

即使文件夹不存在,这仍然可以工作。

为方便人们使用,我们通过通用前缀的概念提供了一组“假装”文件夹。因此,在管理控制台中,文件夹将显示出现在其中。但是,如果该对象随后通过以下方式删除:

aws s3 rm s3://my-buket/fo1/fo2/fo3/foo.txt

结果是文件夹将立即消失,因为它们实际上从未存在!

为了方便起见,一些Amazon S3命令允许您指定PrefixDelimiter。例如,这可以用于仅列出fo3文件夹中的对象。它实际上只是在列出以Key开头的fo1/fo2/fo3/的对象。返回对象的Key时,它将始终具有该对象的完整路径,因为Key实际上的完整路径。 (没有完整的Key之外的文件名的概念。)

因此,如果要列出fo1fo2fo3中的所有文件,则可以列出Prefixfo1的所有文件并接收以fo1/开头的所有对象,但这将包含在子文件夹中的对象,因为它们的前缀都为fo1/

底线:与其考虑老式目录,不如将Amazon S3视为一个平面存储结构。如有必要,您可以使用自己的代码过滤结果。

答案 1 :(得分:0)

您应该检查list_objects_v2()调用返回的值,以了解正在返回的数据。

  • 如果指定了前缀,它将返回已提供的确切前缀的内容。所有子目录均以CommonPrefixes的形式返回。
  • 如果未提供前缀,则返回存储桶中的所有对象。然后,您可以自己在代码中对其进行过滤,如下所示。
import boto3

s3_client = boto3.client('s3', region_name='ap-southeast-2')
s3_bucket = 'my-bucket'
prefix = 'fo1/fo2/fo3/'

response = s3_client.list_objects_v2(Bucket=s3_bucket)
for object in response['Contents']:
    if object['Key'].startswith(prefix):
        print(object['Key'])

答案 2 :(得分:0)

可能以下代码对您有用。我在寻找类似的东西时扩展了约翰的答案。我基本上重新创建了 os.walk() 行为,你可能更熟悉

    import os
    import boto3
    
    # function to replicate os.walk behavior
    def s3walk( locations,prefix):
        
        # recursively add location to roots starting from prefix
        def processLocation( root,prefixLocal,location):
            # add new root location if not available
            if not prefixLocal in root:
                root[prefixLocal]=(set(),set())
            # check how many folders are available after prefix
            remainder = location[len(prefixLocal)+1:]
            structure = remainder.split('/')
            #if we are not yet in the folder of the file we need to continue with a larger prefix
            if len(structure)>1:
                # add folder dir
                root[prefixLocal][0].add(structure[0])
                #make sure file is added allong the way
                processLocation(root, prefixLocal+'/'+structure[0],location )
            else:
                # add to file
                root[prefixLocal][1].add(structure[0])
            
        root={}
        for location in locations:
            processLocation(root,prefix,location)
    
        return root.items()
    
    if __name__ == "__main__":    
        s3_client = boto3.client('s3', region_name='eu-west-3')
        s3_bucket = 'bucket-name'
        prefix = 'fo1/fo2/fo3'
        
        # get list of objects with prefix 
        response = s3_client.list_objects_v2(Bucket=s3_bucket,Prefix=prefix)
        # retrieve key values
        locations = [ object['Key'] for object in response['Contents']]
       
    
    
        for root, (subdir, files) in s3walk(locations,prefix):
            print(root,subdir,files)