如何用boto编程获取Amazon S3文件的MD5校验和

7

相关帖子:     Amazon S3&Checksum,     如何在BASH中将md5总和编码为base64

我必须从具有有限访问权限的S3存储桶下载tar文件。[通常仅授予下载权限]

下载后,我必须检查已下载文件的md5校验和与S3中作为元数据存在的MD5校验和进行比较。

目前,我使用S3文件浏览器手动记录内容头部的“ x-amz-meta-md5”并验证该值是否与已下载文件的计算md5相匹配。

我想知道是否有一种程序化的方法,使用boto捕获S3文件的md5哈希值,就像元数据中所述。

from boto.s3.connection import S3Connection

conn = S3Connection(access_key, secret_key)
bucket=conn.get_bucket("test-bucket")
rs_keys = bucket.get_all_keys()
for key_val in rs_keys:
    print key_val, key_val.**HOW_TO_GET_MD5_FROM_METADATA(?)**

请纠正我理解错误的地方。我正在寻找一种以编程方式捕获头部数据的方法。
3个回答

9
当boto使用任何get_contents_to_*方法下载文件时,它会计算下载的字节的MD5校验和,并将其作为Key对象的md5属性提供。此外,S3在响应中发送一个ETag标头,表示服务器对MD5校验和的想法。这可用作Key对象的etag属性。因此,在下载文件后,您可以比较这两个属性的值以查看它们是否匹配。
如果您想找出S3认为MD5是什么,而不是实际下载文件(如您的示例所示),您可以执行以下操作:
for key_val in rs_keys:
    print key_val, key_val.etag

2
感谢您的建议。Etag值似乎与计算出的MD5校验和不匹配。我在相关帖子中也看到,etag不是MD5的恰当值。 "x-amz-meta-md5"是我的S3文件浏览器中给出MD5值的键。但是,无法以编程方式获取此键的元数据或内容头。 - user1652054
3
“etag”属性的格式将是“797cc49509a9df16481fac4fae144e0a”,而“md5”属性将是“797cc49509a9df16481fac4fae144e0a”。请注意“etag”中的双引号。在比较这些值时,需要考虑到这一点。“x-amz-meta-md5”键不是标准的S3元数据值,而是自定义的。也许这是S3文件浏览器添加的? - garnaat
5
另外还有一条评论。我已经审查了Boto源代码,并确认在下载文件时,Boto会自动将“etag”标头的值与计算出的“md5”值进行比较。如果它们不匹配,它将引发“S3DataError”异常。 - garnaat
2
我们在成功下载文件后遇到了一个问题,即下载的文件损坏了。我希望您指的是boto中的以下代码:文件名:boto / boto / s3 / resumable_download_handler.pycode self.etag_value_for_current_download = f.readline().rstrip('\n') ** # 我们曾经使用基于MD5的正则表达式来确保etag正确读取。由于ETag不一定是MD5,因此现在我们只进行简单的长度检查。

而不是匹配MD5

code请确认是否有另一个文件,用于将下载的文件与md5校验和进行比较。
- user1652054
3
ETag对于MD5校验和来说不是可靠的!从S3文档中可以看到:"ETag可能是也可能不是对象数据的MD5摘要。" 。有关详细信息,请参见此Stack Overflow答案 - gotgenes
1
@garnaat,能否指出S3在哪里检查ETag与计算的MD5值是否一致?我看到_get_file_internal()计算了MD5,但实际上从未检查过它(我不确定为什么)。请参见此处:https://github.com/boto/boto/blob/develop/boto/s3/key.py#L1555 - Ben Hoyt

6
似乎已经确定,如果在运行多部分上传后组装文件,则ETag不是md5sum。我认为在这种情况下,唯一的解决方法是下载文件并在本地执行校验和。如果结果正确,则S3副本必须是好的。如果本地校验和错误,则s3副本可能有问题,或者下载可能失败。如果您不再拥有原始文件或其md5sum的记录,则可能无法解决问题。如果组装文件的md5sum可用,或者有一种方法可以本地计算要通过多部分上传上传的文件的预期ETag,那将是很好的。

0

以下是使用'boto3.resource('s3')'获取md5sum值的方法(还有许多其他方法)

  • Etag与md5sum值相同。
s3_resource = boto3.resource('s3')
head_response = s3_resource.meta.client.head_object(Bucket=bucket_name, Key=object_key)
object_ETag = head_response['ETag'][1:-1]

或者

s3_resource = boto3.resource('s3')
s3_object   = s3_resource.Object(bucket_name, object_key)
object_ETag = s3_object.e_tag.strip('"')

读取并应用 md5sum
s3_resource = boto3.resource('s3')
s3_object   = s3_resource.Object(bucket_name, object_key)
read_body   = s3_object.get()['Body'].read(object_size)
temp_hash   = hashlib.md5()
temp_hash.update(read_body)
s3_md5sum = temp_hash.hexdigest()

或者

s3_resource = boto3.resource('s3')
s3_object = s3_resource.Object(bucket_name, object_key).get()
temp_hash = hashlib.md5()
temp_hash.update(s3_object['Body'].read())
s3_md5_hash = temp_hash.hexdigest()

或者

s3_resource = boto3.resource('s3')
object      = s3_resource.Object(bucket_name,object_key).get()
s3_md5_hash = hashlib.md5(object['Body'].read()).hexdigest()

或者

s3_resource = boto3.resource('s3')
object  = s3_resource.Object(bucket_name,object_key).get()
for byte_block in iter(lambda: object_1['Body'].read(), b''):
    s3_md5_hash.update(byte_block)
s3_md5_hash = s3_md5_hash.hexdigest()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接