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()
对单个键执行 HEAD 请求,即使有问题的对象很大或者您的存储桶中有很多对象,这也很快。
当然,您可能正在检查该对象是否存在,因为您打算使用它。如果是这种情况,您可以忘记 load()
并直接执行 get()
或 download_file()
,然后在那里处理错误情况。
我发现的最简单的方法(可能也是最有效的)是这样的:
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
s3 = boto3.client('s3')
if e.response['ResponseMetadata']['HTTPStatusCode'] == 404:
我不喜欢使用异常来控制流。这是一种适用于 boto3 的替代方法:
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")
list_objects_v2
并将 MaxKeys
设置为 1。
bucket.objects.filter(Prefix=key).limit(1)
并没有限制来自 S3 的实际响应,只限制了客户端返回的集合。相反,您应该按照上面@FangZhang 的建议bucket.objects.filter(Prefix=key, MaxKeys=1)
在 Boto3 中,如果您使用 list_objects 检查文件夹(前缀)或文件。您可以使用响应字典中是否存在“内容”来检查对象是否存在。正如@EvilPuppetMaster 建议的那样,这是另一种避免try/except 捕获的方法
import boto3
client = boto3.client('s3')
results = client.list_objects(Bucket='my-bucket', Prefix='dootdoot.jpg')
return 'Contents' in results
s3:GetObject
权限,只需要 s3:ListBucket
权限
假设您只想检查密钥是否存在(而不是悄悄地覆盖它),请先执行以下检查:
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...
您可以使用 S3Fs,它本质上是一个围绕 boto3 的包装器,它公开了典型的文件系统样式操作:
import s3fs
s3 = s3fs.S3FileSystem()
s3.exists('myfile.txt')
这可以检查前缀和密钥,并且最多获取 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
不仅是 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')
bucket.Object(key).last_modified
。
您可以为此使用 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!")
这里的关键是您要检查的路径是否存在
%timeit
测试来看,这似乎是最快的选择
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)
使用 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)))
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
试试这个简单的
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")
如果您寻求与目录等效的密钥,那么您可能需要这种方法
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
这适用于父键或等同于文件的键或不存在的键。我尝试了上面最喜欢的方法,但在父键上失败了。
如果您的目录或存储桶中少于 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
不存在,此类代码也有效。
http://boto3.readthedocs.io/en/latest/reference/services/s3.html#S3.Client.list_objects_v2
S3_REGION="eu-central-1"
bucket="mybucket1"
name="objectname"
import boto3
from botocore.client import Config
client = boto3.client('s3',region_name=S3_REGION,config=Config(signature_version='s3v4'))
list = client.list_objects_v2(Bucket=bucket,Prefix=name)
for obj in list.get('Contents', []):
if obj['Key'] == name: return True
return False
有一种简单的方法可以检查 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")
object_name
开头的文件,这将是不正确的。例如,如果您检查 my_file.txt
,my_file.txt.oldversion
将返回误报。对于大多数人来说有点极端,但对于像“文件是否存在”这样广泛的东西,您可能会在整个应用程序中使用它可能值得考虑。
对于 boto3,ObjectSummary 可用于检查对象是否存在。
包含存储在 Amazon S3 存储桶中的对象的摘要。此对象不包含包含该对象的完整元数据或其任何内容
import boto3
from botocore.errorfactory import ClientError
def path_exists(path, bucket_name):
"""Check to see if an object exists on S3"""
s3 = boto3.resource('s3')
try:
s3.ObjectSummary(bucket_name=bucket_name, key=path).load()
except ClientError as e:
if e.response['Error']['Code'] == "404":
return False
else:
raise e
return True
path_exists('path/to/file.html')
调用 s3.Client.head_object 来更新 ObjectSummary 资源的属性。
这表明如果您打算不使用 get()
,则可以使用 ObjectSummary
而不是 Object
。 load()
函数不检索它只获取摘要的对象。
我注意到,为了使用 botocore.exceptions.ClientError
捕获异常,我们需要安装 botocore。 botocore 占用了 36M 的磁盘空间。如果我们使用 aws lambda 函数,这尤其会产生影响。如果我们只使用异常来代替它,那么我们可以跳过使用额外的库!
我正在验证文件扩展名为“.csv”
如果桶不存在,这不会抛出异常!
如果桶存在但对象不存在,这不会抛出异常!
如果桶是空的,这会抛出一个异常!
如果存储桶没有权限,这会抛出异常!
代码看起来像这样。请分享您的想法:
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
# 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."
只是按照线程,有人可以得出结论,哪一种是检查 S3 中是否存在对象的最有效方法?
我认为 head_object 可能会赢,因为它只是检查比实际对象本身更轻的元数据
head_object
是最快的方法——它也是 s3.Object('my-bucket', 'dootdoot.jpg').load()
在后台检查对象是否存在的方式。如果您在此方法失败时查看此方法的错误消息,您可以看到这一点。
查看
bucket.get_key(
key_name,
headers=None,
version_id=None,
response_headers=None,
validate=True
)
检查存储桶中是否存在特定键。此方法使用 HEAD 请求来检查密钥是否存在。返回: Key 对象的实例或 None
您可以调用 bucket.get_key(keyname) 并检查返回的对象是否为 None。
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'))
您可以使用 awswrangler 在 1 行中执行此操作。
awswrangler.s3.does_object_exist(path_of_object_to_check)
https://aws-data-wrangler.readthedocs.io/en/stable/stubs/awswrangler.s3.does_object_exist.html
dos_object_exist 方法使用 s3 客户端的 head_object 方法并检查是否引发了 ClientError。如果错误代码为 404,则返回 False。
不定期副业成功案例分享
boto3
,目前您能做的最好的事情似乎是调用head_object
来尝试获取密钥的元数据,然后处理结果错误(如果它不存在)。head_bucket
建议仅适用于存储桶,不适用于对象。我撤回我的建议。 :-)e.response['Error']['Code']
的值类似于"NoSuchKey"
,而不是"404"
。自编写此答案以来,我尚未检查这是否是由于库版本的差异或 API 本身的更改。无论哪种方式,在我的 boto3 版本中,比检查e.response['Error']['Code']
更短的方法是首先只捕获s3.meta.client.exceptions.NoSuchKey
。client
(而不是resource
),则执行s3.head_object(Bucket='my_bucket', Key='my_key')
而不是s3.Object(...).load()