如何从本地文件获取aws s3 etag值?

2024-09-22 16:40:05 发布

您现在位置:Python中文网/ 问答频道 /正文

我想检查从s3下载的文件是否下载良好

所以我决定使用etag值

上传到s3 bucket的对象的etag值与通过python md5找到的值不同

顺便说一下,上传到s3 bucket的对象的etag值和我通过python md5找到的值是不同的

以下是我使用的代码:

#!/usr/bin/env python3.6
import os
import sys
from hashlib import md5
from argparse import ArgumentParser

parser = ArgumentParser(description='Compare an S3 etag to a local file')
parser.add_argument('inputfile', help='The local file')
parser.add_argument('etag', help='The etag from s3')
args = parser.parse_args()

def factor_of_1MB(filesize, num_parts):
  x = filesize / int(num_parts)
  y = x % 1048576
  return int(x + 1048576 - y)

def calc_etag(inputfile, partsize):
  md5_digests = []
  with open(inputfile, 'rb') as f:
    for chunk in iter(lambda: f.read(partsize), b''):
      md5_digests.append(md5(chunk).digest())
  return md5(b''.join(md5_digests)).hexdigest() + '-' + str(len(md5_digests))

def possible_partsizes(filesize, num_parts):
  return lambda partsize: partsize < filesize and (float(filesize) / float(partsize)) <= num_parts

def main():
  filesize  = os.path.getsize(args.inputfile)
  num_parts = int(args.etag.split('-')[1])

  partsizes = [ ## Default Partsizes Map
    8388608, # aws_cli/boto3
    15728640, # s3cmd
    factor_of_1MB(filesize, num_parts) # Used by many clients to upload large files
  ]

  for partsize in filter(possible_partsizes(filesize, num_parts), partsizes):
    if args.etag == calc_etag(args.inputfile, partsize):
      print('Local file matches')
      sys.exit(0)

  print('Couldn\'t validate etag')
  sys.exit(1)

if __name__ == "__main__":
  main()
python3 <file> <aws s3 etag value>

它表示不一致,但与执行以下代码后显示的值相匹配


import hashlib

def calculate_s3_etag(file_path, chunk_size=16 * 1024 * 1024):
    md5s = []

    with open(file_path, 'rb') as fp:
        while True:
            data = fp.read(chunk_size)
            if not data:
                break
            md5s.append(hashlib.md5(data))

    if len(md5s) < 1:
        return '"{}"'.format(hashlib.md5().hexdigest())

    if len(md5s) == 1:
        return '"{}"'.format(md5s[0].hexdigest())

    digests = b''.join(m.digest() for m in md5s)
    digests_md5 = hashlib.md5(digests)
    return '"{}-{}"'.format(digests_md5.hexdigest(), len(md5s))


if __name__ == "__main__":
    print(calculate_s3_etag('./<filename>'))

在这里,我将块大小更改为16。结果表明,运行此代码得到的etag值与我在第一个代码中输入的etag值相匹配

请帮助我如何获取aws etag值

测试是用一个150mb的wmv文件完成的

此外,我测试了57kb的csv文件,它运行良好


Tags: importreturnifs3argsnummd5file