[英]Boto3 S3 Bucket Lifecycle Policy - Delete folders and files after so many days
[英]Boto3 S3: Get files without getting folders
使用 boto3,如何在不检索文件夹的情况下检索 S3 存储桶中的所有文件?
考虑以下文件结构:
file_1.txt
folder_1/
file_2.txt
file_3.txt
folder_2/
folder_3/
file_4.txt
在这个例子中,我只对 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
在这种情况下,总数为 4。
如果我刚刚做了
count = len(s3_client.list_objects(Bucket=bucket_name, Prefix=prefix))
结果将是 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
我只是想:
file.txt
folder_1/file_2.txt
folder_1/file_3.txt
folder_1/folder_2/folder_3/file_4.txt
S3 是一个对象商店。 它不会在目录树下存储文件/对象。 新人总是混淆他们给出的“文件夹”选项,这实际上是对象的任意前缀。
object PREFIX
是一种检索由预定义的修复文件名(键)前缀结构组织的对象的方法,例如 .
您可以想象使用一个文件系统,它不允许您创建目录,但允许您使用斜杠“/”或反斜杠“\\”作为分隔符创建文件名,您可以通过以下方式表示文件的“级别”一个共同的前缀。
因此,在 S3 中,您可以使用以下内容来“模拟不是目录的目录”。
folder1-folder2-folder3-myobject
folder1/folder2/folder3/myobject
folder1\folder2\folder3\myobject
如您所见,无论您使用哪种任意文件夹分隔符(分隔符),对象名称都可以存储在 S3 中。
但是,为了帮助用户将批量文件传输到 S3,aws cli、s3_transfer api 等工具尝试简化步骤并按照您输入的本地文件夹结构创建对象名称。
因此,如果您确定所有 S3 对象都使用/
或\\
作为分隔符,则可以使用 S3transfer 或 AWSCcli 等工具通过使用密钥名称进行简单下载。
这是使用资源迭代器的快速而肮脏的代码。 使用 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)
S3 中没有文件夹。 您拥有的是四个名为的文件:
file_1.txt
folder_1/file_2.txt
folder_1/file_3.txt
folder_1/folder_2/folder_3/file_4.txt
这些是 S3 中对象的实际名称。 如果你想要的是最终结果:
file_1.txt
file_2.txt
file_3.txt
file_4.txt
所有这些都位于本地文件系统上的同一目录中,您需要操作对象的名称以仅去除文件名。 像这样的事情会起作用:
import os.path
full_name = 'folder_1/folder_2/folder_3/file_4.txt'
file_name = os.path.basename(full_name)
然后变量file_name
将包含'file_4.txt'
。
如果您确定没有文件以正斜杠结尾,则过滤出文件夹的一种方法是检查对象的结束字符:
for object_summary in objects.all():
if object_summary.key[-1] == "/":
continue
正如其他答案中所述,s3 实际上没有目录树。 但是有一个方便的解决方法,即通过使用分页器来利用 s3“文件夹”的大小为零这一事实。 如果存储桶中的所有文件的大小 > 0(当然您需要调整您的区域),此代码片段将打印出所需的输出:
bucket_name = "bucketname"
s3 = boto3.client('s3', region_name='eu-central-1')
paginator = s3.get_paginator('list_objects')
[print(page['Key']) for page in paginator.paginate(Bucket=bucket_name).search("Contents[?Size > `0`][]")]
过滤是使用JMESPath完成的。
注意:当然这也会排除大小为 0 的文件,但通常您不需要存储空文件。
使用v2
您还可以获得文件的大小,因此您可以过滤键。
s3_client
.list_objects_v2(bucket: bucket_name, prefix: prefix)
.select { |e| e[:size] > 0 }
.map { |e| e[:key] }
跟进@airborne 的回答,您可以使用 JMESPath 过滤所有以 \ 结尾的键
这仍然会返回空文件,但会过滤掉所有非文件键(除非你有一个以 \ 结尾的文件名,这将迫使你尝试获取内容以确保它是一个文件)。
import boto3
s3 = boto3.client('s3')
def count_files_in_folder(bucket_name: str prefix: str) -> int:
paginator = s3.get_paginator('list_objects_v2')
result = paginator.paginate(Bucket=bucket_name, Prefix=prefix).search("Contents[? !ends_with(key, '/')]")
return len(result)
这将返回所有键而没有任何分页。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.