Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用boto3检查s3中的存储桶中是否存在密钥_Python_Amazon S3_Boto3 - Fatal编程技术网

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

Python 使用boto3检查s3中的存储桶中是否存在密钥,python,amazon-s3,boto3,Python,Amazon S3,Boto3,我想知道boto3中是否存在密钥。我可以循环存储桶中的内容并检查钥匙是否匹配 但这似乎太长了,也太过分了。Boto3官方文件明确说明了如何做到这一点 也许我忽略了显而易见的事实。有人能告诉我如何做到这一点吗。Boto 2的Boto.s3.key.key对象过去有一个exists方法,该方法通过执行HEAD请求并查看结果来检查s3上是否存在密钥,但似乎不再存在。你必须自己做: import boto3 import botocore s3 = boto3.resource('s3') try:

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

但这似乎太长了,也太过分了。Boto3官方文件明确说明了如何做到这一点


也许我忽略了显而易见的事实。有人能告诉我如何做到这一点吗。

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.
    ...
load()
头部请求一个键,这很快,即使所讨论的对象很大或者您的bucket中有很多对象


当然,您可能会检查对象是否存在,因为您正计划使用它。如果是这样的话,您可以忘记
load()
,直接执行
get()
download\u file()
,然后在那里处理错误情况。

我不太喜欢在控制流中使用异常。这是一种适用于BOT3的替代方法:

import boto3

s3 = boto3.resource('s3')
bucket = s3.Bucket('my-bucket')
key = 'dootdoot.jpg'
objs = list(bucket.objects.filter(Prefix=key))
if any([w.key == path_s3 for w in objs]):
    print("Exists!")
else:
    print("Doesn't exist")
退房

bucket.get_key(
    key_name, 
    headers=None, 
    version_id=None, 
    response_headers=None, 
    validate=True
)
检查铲斗内是否存在特定的钥匙。这种方法 使用HEAD请求检查密钥是否存在。返回:一个 键对象的实例或无


您可以调用bucket.get_key(keyname)并检查返回的对象是否为None

在Boto3中,如果您正在使用列表对象检查文件夹(前缀)或文件。您可以使用响应dict中是否存在“Contents”来检查对象是否存在。这是@EvilPuppetMaster建议的另一种避免尝试/例外捕获的方法

import boto3
client = boto3.client('s3')
results = client.list_objects(Bucket='my-bucket', Prefix='dootdoot.jpg')
return 'Contents' in results
我发现的最简单的方法(可能也是最有效的)是:


不仅
客户端
而且
存储桶

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')

如果目录或存储桶中的密钥少于1000,则可以获取一组密钥,并在检查该密钥是否在此集合中后:

files_in_dir = {d['Key'].split('/')[-1] for d in s3_client.list_objects_v2(
Bucket='mybucket',
Prefix='my/dir').get('Contents') or []}
即使
my/dir
不存在,这种代码也可以工作


有一种简单的方法可以检查S3存储桶中是否存在文件。我们不需要为此使用异常

sesssion = boto3.Session(aws_access_key_id, aws_secret_access_key)
s3 = session.client('s3')

object_name = 'filename'
bucket = 'bucketname'
obj_status = s3.list_objects(Bucket = bucket, Prefix = object_name)
if obj_status.get('Contents'):
    print("File exists")
else:
    print("File does not exists")

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
对于boto3,可用于检查对象是否存在

包含存储在AmazonS3存储桶中的对象的摘要。此对象不包含对象的完整元数据或其任何内容

调用s3.Client.head_对象以更新ObjectSummary资源的属性


这表明,如果您计划不使用
get()
,则可以使用
ObjectSummary
而不是
Object
load()
函数不检索对象,它只获取摘要。

如果您查找与目录等效的键,则可能需要这种方法

session = boto3.session.Session()
resource = session.resource("s3")
bucket = resource.Bucket('mybucket')

key = 'dir-like-or-file-like-key'
objects = [o for o in bucket.objects.filter(Prefix=key).limit(1)]    
has_key = len(objects) > 0

这适用于父密钥、等同于文件的密钥或不存在的密钥。我尝试了上面喜欢的方法,但在父密钥上失败了。

我注意到,为了使用
botocore.exceptions.ClientError
捕获异常,我们需要安装botocore。botocore占用36M磁盘空间。如果我们使用aws lambda函数,这尤其会产生影响。如果我们只是使用exception,那么我们可以跳过使用额外的库

  • 我正在验证文件扩展名是否为“.csv”
  • 如果bucket不存在,则不会引发异常
  • 如果bucket存在但对象不存在,则不会引发异常
  • 如果桶为空,则抛出异常
  • 如果bucket没有权限,则抛出异常
代码如下所示。请分享你的想法:

import boto3
import traceback

def download4mS3(s3bucket, s3Path, localPath):
    s3 = boto3.resource('s3')

    print('Looking for the csv data file ending with .csv in bucket: ' + s3bucket + ' path: ' + s3Path)
    if s3Path.endswith('.csv') and s3Path != '':
        try:
            s3.Bucket(s3bucket).download_file(s3Path, localPath)
        except Exception as e:
            print(e)
            print(traceback.format_exc())
            if e.response['Error']['Code'] == "404":
                print("Downloading the file from: [", s3Path, "] failed")
                exit(12)
            else:
                raise
        print("Downloading the file from: [", s3Path, "] succeeded")
    else:
        print("csv file not found in in : [", s3Path, "]")
        exit(12)
试试这个简单的

import boto3
s3 = boto3.resource('s3')
bucket = s3.Bucket('mybucket_name') # just Bucket name
file_name = 'A/B/filename.txt'      # full file path
obj = list(bucket.objects.filter(Prefix=file_name))
if len(obj) > 0:
    print("Exists")
else:
    print("Not Exists")

这里有一个适合我的解决方案。需要注意的是,我提前知道密钥的确切格式,所以我只列出了单个文件

import boto3

# The s3 base class to interact with S3
class S3(object):
  def __init__(self):
    self.s3_client = boto3.client('s3')

  def check_if_object_exists(self, s3_bucket, s3_key):
    response = self.s3_client.list_objects(
      Bucket = s3_bucket,
      Prefix = s3_key
      )
    if 'ETag' in str(response):
      return True
    else:
      return False

if __name__ == '__main__':
  s3  = S3()
  if s3.check_if_object_exists(bucket, key):
    print "Found S3 object."
  else:
    print "No object found."
您可以使用,它本质上是boto3的包装器,公开典型的文件系统样式操作:

import s3fs
s3 = s3fs.S3FileSystem()
s3.exists('myfile.txt')

你可以用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!")

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

使用
get()
方法非常简单

import botocore
from boto3.session import Session
session = Session(aws_access_key_id='AWS_ACCESS_KEY',
                aws_secret_access_key='AWS_SECRET_ACCESS_KEY')
s3 = session.resource('s3')
bucket_s3 = s3.Bucket('bucket_name')

def not_exist(file_key):
    try:
        file_details = bucket_s3.Object(file_key).get()
        # print(file_details) # This line prints the file details
        return False
    except botocore.exceptions.ClientError as e:
        if e.response['Error']['Code'] == "NoSuchKey": # or you can check with e.reponse['HTTPStatusCode'] == '404'
            return True
        return False # For any other error it's hard to determine whether it exists or not. so based on the requirement feel free to change it to True/ False / raise Exception

print(not_exist('hello_world.txt')) 

按照这个思路,有人能断定哪种方法是检查S3中是否存在对象的最有效方法吗


我认为head_对象可能会赢,因为它只检查比实际对象本身轻的元数据

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

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...

这可以同时检查前缀和键,最多获取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

使用
objects.filter
并检查结果列表是检查S3存储桶中是否存在文件的最快方法

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

s3_file_exists = lambda filename: bool(list(bucket.objects.filter(Prefix=filename)))
上述函数假定已声明
bucket
变量

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

s3_file_exists = lambda filename, bucket: bool(list(bucket.objects.filter(Prefix=filename)))

谢谢你的快速回复。我只需要对boto3使用相同的方法。对于
boto3
,您目前能做的最好的方法似乎是调用以尝试获取密钥的元数据,然后处理由此产生的错误(如果它不存在)。@Leonid您当然可以,但前提是将其包装在函数或方法中,这取决于您。我对示例代码做了一些修改,使
存在
布尔值消失了,更清楚的是(我希望!)人们应该根据自己的情况调整它;不适合我。在boto3版本1.5.26上,我看到
e.response['Error']['code']
的值类似于
“NoSuchKey”
,而不是
“404”
。我还没有检查这是否是由于库版本的不同,还是因为编写了这个答案后API本身发生了变化。不管怎样,在我的版本中
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...
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
s3_file_exists = lambda filename: bool(list(bucket.objects.filter(Prefix=filename)))
s3_file_exists = lambda filename, bucket: bool(list(bucket.objects.filter(Prefix=filename)))