使用boto3检查s3中存储桶中是否存在密钥

Pra*_*gam 125 python amazon-s3 boto3

我想知道boto3中是否存在密钥.我可以循环存储桶内容并检查密钥是否匹配.

但这似乎更长,而且有点矫枉过正.Boto3官方文档明确说明了如何做到这一点.

可能是我错过了显而易见的事.任何人都可以指出我如何实现这一目标.

Wan*_*uta 153

Boto 2的boto.s3.key.Key对象曾经有一个exists方法,通过执行HEAD请求并查看结果来检查S3上是否存在密钥,但似乎不再存在.你必须自己做:

import boto3
import botocore

s3 = boto3.resource('s3')

try:
    s3.Object('my-bucket', 'dootdoot.jpg').load()
except botocore.exceptions.ClientError as e:
    if e.response['Error']['Code'] == "404":
        # The object does not exist.
        ...
    else:
        # Something else has gone wrong.
        raise
else:
    # The object does exist.
    ...
Run Code Online (Sandbox Code Playgroud)

load() 对单个键执行HEAD请求,即使相关对象很大或者您的存储桶中有很多对象,它也很快.

当然,您可能正在检查对象是否存在,因为您计划使用它.如果是这种情况,您可以忘记load()并执行get()download_file()直接执行,然后在那里处理错误情况.

  • 对于`boto3`,你现在最好的做法就是调用[`head_object`](https://boto3.readthedocs.org/en/latest/reference/services/s3.html#S3.Client. head_object)尝试获取密钥的元数据,然后处理产生的错误(如果它不存在). (9认同)
  • 如果您使用 s3 `client`(而不是 `resource`),则执行 `s3.head_object(Bucket='my_bucket', Key='my_key')` 而不是 `s3.Object(...)。加载()` (7认同)
  • -1; 对我不起作用。在 boto3 版本 1.5.26 上,我看到 `e.response['Error']['Code']` 的值类似于 `"NoSuchKey"`,而不是 `"404"`。自从编写此答案以来,我还没有检查这是否是由于库版本的差异或 API 本身的更改造成的。无论哪种方式,在我的 boto3 版本中,比检查 `e.response['Error']['Code']` 更短的方法是首先只捕获 `s3.meta.client.exceptions.NoSuchKey`。 (4认同)

Evi*_*ter 96

我不是使用控制流异常的忠实粉丝.这是另一种适用于boto3的方法:

import boto3

s3 = boto3.resource('s3')
bucket = s3.Bucket('my-bucket')
key = 'dootdoot.jpg'
objs = list(bucket.objects.filter(Prefix=key))
if len(objs) > 0 and objs[0].key == key:
    print("Exists!")
else:
    print("Doesn't exist")
Run Code Online (Sandbox Code Playgroud)

  • 这不算是列表请求(比获取费用高12.5倍)吗?如果你为1亿个对象执行此操作,那可能会有点昂贵...我觉得捕获异常方法不幸是迄今为止最好的. (18认同)
  • 每个请求的列表可能是12.5倍,但单个请求也可以返回1亿个对象,其中单个get只能返回一个.因此,在您的假设情况下,使用列表获取所有1亿,然后在本地进行比较会比使用100米个人获取更便宜.更不用说1000倍速,因为你不需要每个对象的http往返. (17认同)
  • 再次运行调试后,看起来 `bucket.objects.filter(Prefix=key).limit(1)` 并不限制来自 S3 的实际响应,仅限制客户端返回的集合。相反,你应该像@FangZhang上面建议的那样 `bucket.objects.filter(Prefix=key, MaxKeys=1)` (3认同)
  • 感谢 EvilPuppetMaster 的更新。不幸的是,当我最后检查时,我没有列表存储桶访问权限。你的回答很适合我的问题,所以我已经投票给你了。但是我很久以前就已经将第一个回复标记为答案。谢谢你的帮助。 (2认同)
  • @user3186866那是因为S3实际上没有“文件夹”。所有对象都以文件形式存在于其给定路径中。文件夹是帮助我们组织和理解存储结构的工具,但实际上,S3 存储桶就是存储桶。 (2认同)
  • 使用 S3 客户端的“list_objects_v2”并将“MaxKeys”设置为 1。 (2认同)

o_c*_*o_c 85

我找到的最简单的方法(也许最有效)是:

import boto3
from botocore.errorfactory import ClientError

s3 = boto3.client('s3')
try:
    s3.head_object(Bucket='bucket_name', Key='file_path')
except ClientError:
    # Not found
    pass
Run Code Online (Sandbox Code Playgroud)

  • 我认为添加此测试会让您更加自信,该对象确实不存在,而不是引发异常的其他错误 - 请注意'e'是ClientError异常实例:`if e.response ['ResponseMetadata'] [ 'HTTPStatusCode'] == 404:` (12认同)
  • 注意:您不必传递aws_access_key_id / aws_secret_access_key等。如果使用角色或您在.aws配置中包含密钥,则可以简单地执行`s3 = boto3.client('s3')`。 (2认同)
  • @Taylor是一个get请求,但没有数据传输。 (2认同)
  • ClientError 是 400 的总称,而不仅仅是 404,因此它并不健壮。 (2认同)
  • @mickzer你是对的。最好排除 S3.Client.exceptions.NoSuchKey。 (2认同)

Luc*_*orr 17

在Boto3中,如果您使用list_objects检查文件夹(前缀)或文件.您可以使用响应dict中"Contents"的存在来检查对象是否存在.这是另一种避免try/except捕获的方法,如@EvilPuppetMaster建议的那样

import boto3
client = boto3.client('s3')
results = client.list_objects(Bucket='my-bucket', Prefix='dootdoot.jpg')
return 'Contents' in results
Run Code Online (Sandbox Code Playgroud)

  • 这最多只能返回1000个对象!https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.list_objects (3认同)
  • 在这方面有问题。list_objects("2000") 将返回诸如“2000-01”、“2000-02”之类的键 (2认同)

Vin*_*ceP 17

您可以使用S3Fs,它本质上是 boto3 的包装器,用于公开典型的文件系统样式操作:

import s3fs
s3 = s3fs.S3FileSystem()
s3.exists('myfile.txt')
Run Code Online (Sandbox Code Playgroud)

  • 虽然我认为这可行,但问题是如何使用 boto3 做到这一点;在这种情况下,不安装额外的库就可以解决问题。 (5认同)

Ash*_*uGG 14

您可以使用 Boto3 来实现此目的。

import boto3
s3 = boto3.resource('s3')
bucket = s3.Bucket('my-bucket')
objs = list(bucket.objects.filter(Prefix=key))
if(len(objs)>0):
    print("key exists!!")
else:
    print("key doesn't exist!")
Run Code Online (Sandbox Code Playgroud)

这里的key是你要检查的路径是否存在


mar*_*vls 13

假设您只想检查密钥是否存在(而不是悄悄地覆盖它),请先执行此检查:

import boto3

def key_exists(mykey, mybucket):
  s3_client = boto3.client('s3')
  response = s3_client.list_objects_v2(Bucket=mybucket, Prefix=mykey)
  if response:
      for obj in response['Contents']:
          if mykey == obj['Key']:
              return True
  return False

if key_exists('someprefix/myfile-abc123', 'my-bucket-name'):
    print("key exists")
else:
    print("safe to put new bucket object")
    # try:
    #     resp = s3_client.put_object(Body="Your string or file-like object",
    #                                 Bucket=mybucket,Key=mykey)
    # ...check resp success and ClientError exception for errors...
Run Code Online (Sandbox Code Playgroud)


Vit*_*ich 10

不仅client但是bucket太:

import boto3
import botocore
bucket = boto3.resource('s3', region_name='eu-west-1').Bucket('my-bucket')

try:
  bucket.Object('my-file').get()
except botocore.exceptions.ClientError as ex:
  if ex.response['Error']['Code'] == 'NoSuchKey':
    print('NoSuchKey')
Run Code Online (Sandbox Code Playgroud)

  • 您可能不想获取该对象,而只是看看它是否在那里。你可以像这里的其他例子一样使用一个方法来引导对象,比如`bucket.Object(key).last_modified`。 (4认同)

Fan*_*ang 9

这可以检查前缀和键,并且最多获取 1 个键。

def prefix_exits(bucket, prefix):
    s3_client = boto3.client('s3')
    res = s3_client.list_objects_v2(Bucket=bucket, Prefix=prefix, MaxKeys=1)
    return 'Contents' in res
Run Code Online (Sandbox Code Playgroud)

  • 这个答案看起来是许多其他答案中最好的。唯一的问题是,如果存在带有键“Key12”的对象,则前缀 =“Key1”将返回“True”。要检查确切的键是否存在,最后一行应固定为类似的内容(抱歉代码丑陋,我需要将其放在注释中):`return 'Contents' in response and len(response['Contents'] ) > 0 和响应['Contents'][0]中的'Key'和响应['Contents'][0]['Key'] == prefix` (6认同)

Viv*_*vek 6

import boto3
client = boto3.client('s3')
s3_key = 'Your file without bucket name e.g. abc/bcd.txt'
bucket = 'your bucket name'
content = client.head_object(Bucket=bucket,Key=s3_key)
    if content.get('ResponseMetadata',None) is not None:
        print "File exists - s3://%s/%s " %(bucket,s3_key) 
    else:
        print "File does not exist - s3://%s/%s " %(bucket,s3_key)
Run Code Online (Sandbox Code Playgroud)


And*_*gan 6

FWIW,这是我正在使用的非常简单的功能

import boto3

def get_resource(config: dict={}):
    """Loads the s3 resource.

    Expects AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to be in the environment
    or in a config dictionary.
    Looks in the environment first."""

    s3 = boto3.resource('s3',
                        aws_access_key_id=os.environ.get(
                            "AWS_ACCESS_KEY_ID", config.get("AWS_ACCESS_KEY_ID")),
                        aws_secret_access_key=os.environ.get("AWS_SECRET_ACCESS_KEY", config.get("AWS_SECRET_ACCESS_KEY")))
    return s3


def get_bucket(s3, s3_uri: str):
    """Get the bucket from the resource.
    A thin wrapper, use with caution.

    Example usage:

    >> bucket = get_bucket(get_resource(), s3_uri_prod)"""
    return s3.Bucket(s3_uri)


def isfile_s3(bucket, key: str) -> bool:
    """Returns T/F whether the file exists."""
    objs = list(bucket.objects.filter(Prefix=key))
    return len(objs) == 1 and objs[0].key == key


def isdir_s3(bucket, key: str) -> bool:
    """Returns T/F whether the directory exists."""
    objs = list(bucket.objects.filter(Prefix=key))
    return len(objs) > 1
Run Code Online (Sandbox Code Playgroud)


neh*_*iah 5

使用objects.filter和检查结果列表是迄今为止检查 S3 存储桶中是否存在文件的最快方法。.

使用这个简洁的 oneliner,当您必须将它扔到现有项目中而不修改大部分代码时,它会减少干扰。

s3_file_exists = lambda filename: bool(list(bucket.objects.filter(Prefix=filename)))
Run Code Online (Sandbox Code Playgroud)

上述函数假定bucket变量已经声明。

您可以扩展 lambda 以支持其他参数,例如

s3_file_exists = lambda filename, bucket: bool(list(bucket.objects.filter(Prefix=filename)))
Run Code Online (Sandbox Code Playgroud)

  • 我认为这是最好的答案。 (2认同)

Ras*_*hid 5

现在是 2023 年了,以上都对我不起作用。这是为我做的版本:

import boto3
import botocore
s3 = boto3.client('s3')
try:  
    s3.head_object(Bucket='YOUR_BUCKET_NAME', Key=object_name)
except botocore.exceptions.ClientError as error:
    if error.response['Error']['Code']:
        print("Object does not exist!")
    else:
        print("Object exists!")
Run Code Online (Sandbox Code Playgroud)

如果您确实拥有权限并且请求一切正常,那么如果该对象不存在,您将收到 404。该请求还会返回 400 和 403,因此如果您想更具体地了解错误处理,您可以检查这些。