【问题标题】:boto get md5 s3 fileboto 获取 md5 s3 文件
【发布时间】:2014-12-12 12:00:15
【问题描述】:

我有一个使用案例,我使用分段上传将数百个文件上传到我的 S3 存储桶。每次上传后,我需要确保上传的文件没有损坏(基本上检查数据完整性)。目前,上传文件后,我重新下载并计算内容字符串上的md5,并将其与本地文件的md5进行比较。所以像:

conn = S3Connection('access key', 'secretkey')
bucket = conn.get_bucket('bucket_name')
source_path = 'file_to_upload'
source_size = os.stat(source_path).st_size

mp = bucket.initiate_multipart_upload(os.path.basename(source_path))
chunk_size = 52428800
chunk_count = int(math.ceil(source_size / chunk_size))

for i in range(chunk_count + 1):
   offset = chunk_size * i
   bytes = min(chunk_size, source_size - offset)
   with FileChunkIO(source_path, 'r', offset=offset, bytes=bytes) as fp:
       mp.upload_part_from_file(fp, part_num=i + 1, md5=k.compute_md5(fp, bytes))
mp.complete_upload()
    
obj_key = bucket.get_key('file_name')
print(obj_key.md5) #prints None
print(obj_key.base64md5) #prints None

content = bucket.get_key('file_name').get_contents_as_string()
# compute the md5 on content

这种方法很浪费,因为它会使带宽使用量翻倍。我试过了

bucket.get_key('file_name').md5 
bucket.get_key('file_name').base64md5 

但两者都返回 None。

有没有其他方法可以在不下载整个东西的情况下实现md5

【问题讨论】:

    标签: python amazon-web-services amazon-s3 md5 boto


    【解决方案1】:

    是的
    使用bucket.get_key('file_name').etag[1 :-1]
    这样就可以得到key的MD5而不用下载它的内容。

    【讨论】:

    • 请注意,它仅适用于单个部分上传的文件。如果使用多部分下载,则 etag 不是 MD5,您必须下载文件才能计算哈希
    • 谢谢@Beka 不知道
    • 我不同意@Beka,您可以在不下载文件的情况下找出亚马逊正在使用的 md5。有关更多信息,请参阅此问题:stackoverflow.com/questions/6591047/…
    • 看来你是对的,它相当复杂,你最好知道你使用的块的大小,但你可以不用下载文件来计算
    【解决方案2】:

    使用 boto3,我使用 head_object 来检索 ETag。

    import boto3
    import botocore
    
    def s3_md5sum(bucket_name, resource_name):
        try:
            md5sum = boto3.client('s3').head_object(
                Bucket=bucket_name,
                Key=resource_name
            )['ETag'][1:-1]
        except botocore.exceptions.ClientError:
            md5sum = None
            pass
        return md5sum
    

    【讨论】:

    【解决方案3】:

    自 2016 年以来,无需任何额外对象检索的最佳方法是在 PutObject 请求期间提供 --content-md5 参数。 AWS 将验证提供的 MD5 是否与他们计算的 MD5 匹配。这也适用于分段上传和 >5GB 的对象。

    来自知识中心的示例调用:

    aws s3api put-object --bucket awsexamplebucket --key awsexampleobject.txt --body awsexampleobjectpath --content-md5 examplemd5value1234567== --metadata md5checksum=examplemd5value1234567==
    

    https://aws.amazon.com/premiumsupport/knowledge-center/data-integrity-s3/

    【讨论】:

      【解决方案4】:

      您可以在不下载文件的情况下从e_tag 属性中恢复md5,如下所示:

      boto3.resource('s3').Object(<BUCKET_NAME>, file_path).e_tag[1 :-1]
      

      然后用这个函数比较classic s3文件:

      def md5_checksum(file_path):
          m = hashlib.md5()
          with open(file_path, 'rb') as f:
              for data in iter(lambda: f.read(1024 * 1024), b''):
                  m.update(data)
          return m.hexdigest()
      

      或者这个函数用于多部分文件:

      def etag_checksum(file_path, chunk_size=8 * 1024 * 1024):
          md5s = []
          with open(file_path, 'rb') as f:
              for data in iter(lambda: f.read(chunk_size), b''):
                  md5s.append(hashlib.md5(data).digest())
          m = hashlib.md5("".join(md5s))
          return '{}-{}'.format(m.hexdigest(), len(md5s))
      

      最后用这个函数在两者之间进行选择:

      def md5_compare(file_path, s3_file_md5):
          if '-' in s3_file_md5 and s3_file_md5 == etag_checksum(file_path):
              return True
          if '-' not in s3_file_md5 and s3_file_md5 == md5_checksum(file_path):
              return True
          print("MD5 not equals for file " + file_path)
          return False
      

      归功于:https://zihao.me/post/calculating-etag-for-aws-s3-objects/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-15
        • 2021-01-04
        • 2015-04-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多