Boto3 S3:获取文件而不获取文件夹

Vin*_*oft 3 python amazon-s3 amazon-web-services boto3

使用boto3,如何在不检索文件夹的情况下检索S3存储桶中的所有文件?

请考虑以下文件结构:

file_1.txt
folder_1/
    file_2.txt
    file_3.txt
    folder_2/
        folder_3/
            file_4.txt
Run Code Online (Sandbox Code Playgroud)

在这个例子中我只对4个文件感兴趣.

编辑:

手动解决方案是:

def count_files_in_folder(prefix):
    total = 0
    keys = s3_client.list_objects(Bucket=bucket_name, Prefix=prefix)
    for key in keys['Contents']:
        if key['Key'][-1:] != '/':
            total += 1
    return total
Run Code Online (Sandbox Code Playgroud)

在这种情况下,总数将是4.

如果我这样做的话

count = len(s3_client.list_objects(Bucket=bucket_name, Prefix=prefix))
Run Code Online (Sandbox Code Playgroud)

结果将是7个对象(4个文件和3个文件夹):

file.txt
folder_1/
folder_1/file_2.txt
folder_1/file_3.txt
folder_1/folder_2/
folder_1/folder_2/folder_3/
folder_1/folder_2/folder_3/file_4.txt
Run Code Online (Sandbox Code Playgroud)

我只是想:

file.txt
folder_1/file_2.txt
folder_1/file_3.txt  
folder_1/folder_2/folder_3/file_4.txt
Run Code Online (Sandbox Code Playgroud)

moo*_*oot 15

S3是一个OBJECT STORE.它不提供目录服务.新来者总是混淆他们给出的"文件夹"选项,这实际上是对象的任意前缀.

object PREFIX是一种通过修复分组结构检索对象的方法.

您可以想象使用不允许您创建目录的文件系统,但允许您使用斜杠"/"或反斜杠"\"作为分隔符创建文件名,并且您可以通过以下方式表示文件的"级别"一个共同的前缀.

因此,在S3中,您使用以下"模拟目录"而不是目录.

folder1-folder2-folder3-myobject
folder1/folder2/folder3/myobject
folder1\folder2\folder3\myobject
Run Code Online (Sandbox Code Playgroud)

但是,为了帮助用户将批量文件传输到S3,aws cli,s3_transfer api等工具尝试简化步骤,并按照输入的本地文件夹结构创建对象名称.

因此,如果您确定所有S3对象都使用"/"作为分隔符,您实际上可以使用密钥名称进行简单下载(您必须首先通过提取密钥文件夹来创建文件夹,如分隔符结构)

这是使用资源迭代器的快速而脏的代码.使用s3.resource.object.filter将返回与list_objects()/ list_objects_v2()没有相同1000个键限制的迭代器.

import os 
import boto3
s3 = boto3.resource('s3')
mybucket = s3.Bucket("mybucket")
# if blank prefix is given, return everything)
bucket_prefix="/some/prefix/here"
objs = mybucket.objects.filter(
    Prefix = bucket_prefix)

for obj in objs:
    path, filename = os.path.split(obj.key)
    # boto3 s3 download_file will throw exception if folder not exists
    try:
        os.makedirs(path) 
    except FileExistsError:
        pass
    mybucket.download_file(obj.key, obj.key)
Run Code Online (Sandbox Code Playgroud)

  • 解释否决票:这并没有真正解决问题,老实说,我有点困惑为什么会接受这个,而不是下面的答案之一,实际上有助于过滤掉这些不需要的项目。顺便说一句,“文件夹不是真正的文件夹”这件事很好,但在这里几乎没有实际影响。如果 AWS 控制台和文档本身也将它们称为“文件夹”并以这种方式对待它们,那么这一点也会变得混乱。 (5认同)

gar*_*aat 7

S3中没有文件夹.你有四个名为的文件:

file_1.txt
folder_1/file_2.txt
folder_1/file_3.txt
folder_1/folder_2/folder_3/file_4.txt
Run Code Online (Sandbox Code Playgroud)

这些是S3中对象的实际名称.如果你想要的是最终:

file_1.txt
file_2.txt
file_3.txt
file_4.txt
Run Code Online (Sandbox Code Playgroud)

所有这些都位于本地文件系统的同一目录中,您需要操作对象的名称以仅删除文件名.像这样的东西会起作用:

import os.path

full_name = 'folder_1/folder_2/folder_3/file_4.txt'
file_name = os.path.basename(full_name)
Run Code Online (Sandbox Code Playgroud)

然后变量file_name将包含'file_4.txt'.

  • 不,S3中确实没有文件夹.如果您执行存储桶的``ListObjects`` API请求,您将看到的只是上面列出的四个文件名.S3允许您指定分隔符(默认为"/"),然后它将允许您导航对象,就好像有文件夹但S3中没有存储表示文件夹``folder1``的对象.没有办法告诉S3服务只返回基本文件名.您必须获取所有对象的列表,然后操纵对象名称以仅提取基本文件名. (3认同)
  • 不,先生,list_objects 将返回 7 个对象http://boto3.readthedocs.io/en/latest/reference/services/s3.html#S3.Client.list_objects (2认同)
  • @garnaat这是一个很好的答案,但它需要某种重复的文件名处理。如果“folder1/file.txt”和“folder2/file.txt”存在,则当您将两者保存到同一本地目录时,其中一个会覆盖另一个。 (2认同)
  • 我对 S3 中不存在的文件夹感到非常困惑,因为(正如我刚才所说)控制台上的一个大按钮会创建文件夹,当我调用 list_objects 时,我会检索文件夹。但你是对的,我在 S3 文档中多次指出文件夹不存在。那么它们怎么会以零尺寸物体的形式存在呢?! (2认同)

bto*_*om5 7

如果您确定没有文件以正斜杠结尾,则过滤出文件夹的一种方法是检查对象的结束字符:

for object_summary in objects.all():
    if object_summary.key[-1] == "/":
        continue
Run Code Online (Sandbox Code Playgroud)