• AWS S3 大文件分片上传


    分段上传允许上传单个对象作为一组分段。每个分段都是对象数据的连续部分。您可以独立上传以及按任意顺序上传这些对象分段。如果任意分段传输失败,可以重新传输该分段且不会影响其他分段。上传完所有的数据元分段后,Amazon S3 将汇集这些分段并创建数据元。一般而言,如果您的对象大小达到了 100 MB,您应该考虑使用分段上传,而不是在单个操作中上传对象。

    分段上传流程

    分段上分为三个步骤:开始上传、上传对象分段,以及在上传所有分段后完成分段上传。收到完成分段上传请求后,Amazon S3 将构建来自已上传分段的数据元,然后您可以像在您的存储桶中访问任何其他对象一样访问该对象。

    您可以列出所有正在执行的分段上传,或者获取为特定分段上传操作上传的分段列表。以上每个操作都在本节中进行了说明。

    分段上传开始

    当您发送请求以开始分段上传时,Amazon S3 将返回具有上传 ID 的响应,此 ID 是分段上传的唯一标识符。无论您何时上传分段、列出分段、完成上传或停止上传,您都必须包括此上传 ID。如果您想要提供描述已上传的对象的任何元数据,必须在请求中提供它以开始分段上传。

    分段上传

    上传分段时,除了指定上传 ID,还必须指定分段编号。您可以选择 1 和 10000 之间的任意分段编号。分段编号在您正在上传的对象中唯一地识别分段及其位置。您选择的分段编号不必是连续序列(例如,它可以是 1、5 和 14)。如果您使用之前上传的分段的同一分段编号上传新分段,则之前上传的分段将被覆盖。

    无论您何时上传分段,Amazon S3 都将在其响应中返回 ETag 标头。对于每个分段上传,您必须记录分段编号和 ETag 值。您必须在随后的请求中包括这些值以完成分段上传。

    分段上传完成

    完成分段上传时,Amazon S3 通过按升序的分段编号规范化分段来创建对象。如果在开始分段上传请求中提供了任何对象元数据,则 Amazon S3 会将该元数据与对象相关联。成功完成请求后,分段将不再存在。

    完成分段上传请求必须包括上传 ID 以及分段编号和相应的 ETag 值的列表。Amazon S3 响应包括可唯一地识别组合对象数据的 ETag。此 ETag 无需成为对象数据的 MD5 哈希。

    您可以选择停止分段上传。停止分段上传后,无法再次使用该上传 ID 上传任何分段。然后,释放取消的分段上传的任何分段的所有存储空间。如果有任何分段上传正在进行,则即使在您停止后,它们仍然可能会成功或失败。要释放所有分段使用的所有存储,必须仅在完成所有分段的上传后才停止分段上传。

    参考链接: https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/mpuoverview.html

    示例代码:

    import os
    import redis
    import boto3
    
    
    ################################## ##################################
    # 把图片数据上传到本地 redis 中
    
    conn = redis.Redis()
    
    
    def store_img2redis():
        """
        把图片数据存入到 redis 的列表中
        """
    
        with open('/Users/zxk/Desktop/1min1sec.mp4', 'rb') as f:
            while True:
                bytes_data = f.read(1024 * 1024 * 6)   # 每次读取 6 M的数据
                if not bytes_data:
                    return
                conn.rpush('gopher_img', bytes_data)
    
    
    ################################# #################################
    # 把图片数据从 redis 中迭代读取出来,并分片上传到 S3 中
    
    def list_iter(name, count=2):
        """
        迭代获取 redis 列表中的数据
        """
        idx = 0
        while True:
            data = conn.lrange(name, idx, idx + count - 1)
            if not data:
                return
    
            idx += count
    
            for item in data:
                yield item
    
    
    client = boto3.client(
        's3',
        aws_access_key_id=os.getenv(
            'AWS_S3_ACCESS_KEY_ID', 'xxxxxxxxxxxxxxxxxxxx'),
        aws_secret_access_key=os.getenv(
            'AWS_S3_SECRET_ACCESS_KEY', 'xxyxyxxyxyxxyxyxyxxy'),
        region_name=os.getenv('AWS_S3_REGION_NAME', 'cn-northwest-1')
    )
    
    
    part_info = {
        'Parts': []
    }
    
    
    def create_multipart_upld():
        """
        分片上传功能的函数
        """
        response = client.create_multipart_upload(
            Bucket=bucket名称, Key='static/gopher.mp4')   # This action initiates a multipart upload and returns an upload ID
        print(response)
    
        part_no = 1     # 用于标识分片上传时的数据块号,即 PartNumber
        for part_bytes in list_iter('gopher_img'):
            print('upload ID:', response['UploadId'])
            part = client.upload_part(
                Body=part_bytes,
                Bucket=bucket名称,
                Key='static/gopher.mp4',
                PartNumber=part_no,     # 这个号要唯一,不唯一的话会把前面相同的PartNumber数据覆盖掉
                UploadId=response['UploadId'],
            )
    
            # 每个 PartNumber 和 ETag 要对应起来
            part_info['Parts'].append({
                'PartNumber': part_no,
                'ETag': part['ETag']
            })
            part_no += 1
        print('part_info:', part_info)
    
        # Completes a multipart upload by assembling previously uploaded parts. 告诉 AWS S3 已经分片上传完了
        complete_rsp = client.complete_multipart_upload(Bucket=bucket名称,
                                                        Key='static/gopher.mp4',
                                                        UploadId=response['UploadId'],
                                                        MultipartUpload=part_info)
        print('complete_rsp:', complete_rsp)
    
    
    create_multipart_upld()
    
    
    """
    输出结果:
    {'ResponseMetadata': {'RequestId': 'NVDSJHCASJD', 'HostId': 'MCDCSNDSNAnvdsahnvdasjk', 'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amz-id-2': 'aJGYwJy7UhP/PtFW/OprgKvLxDMi9fUZJuvR2925pnzvk=', 'x-amz-request-id': 'NVDSJHCASJD', 'date': 'Fri, 02 Jul 2021 15:22:52 GMT', 'transfer-encoding': 'chunked', 'server': 'AmazonS3'}, 'RetryAttempts': 0}, 'Bucket': 'bucket-test', 'Key': 'static/gopher.mp4', 'UploadId': '5GuYO83ZlEkhPzApxM49nxvdpvNGF3AQkG0FZ..ALMMpoZGm8KaFBVZOf2qZWY3PGBRgDXZDZXUy_tiNNYeBUOpuUbIm_meupByUIZTdzy4CYkiy0CXKrDf1_lKeGoiv'}
    upload ID: 5GuYO83ZlEkhPzApxM49nxvdpvNGF3AQkG0FZ..ALMMpoZGm8KaFBVZOf2qZWY3PGBRgDXZDZXUy_tiNNYeBUOpuUbIm_meupByUIZTdzy4CYkiy0CXKrDf1_lKeGoiv
    upload ID: 5GuYO83ZlEkhPzApxM49nxvdpvNGF3AQkG0FZ..ALMMpoZGm8KaFBVZOf2qZWY3PGBRgDXZDZXUy_tiNNYeBUOpuUbIm_meupByUIZTdzy4CYkiy0CXKrDf1_lKeGoiv
    upload ID: 5GuYO83ZlEkhPzApxM49nxvdpvNGF3AQkG0FZ..ALMMpoZGm8KaFBVZOf2qZWY3PGBRgDXZDZXUy_tiNNYeBUOpuUbIm_meupByUIZTdzy4CYkiy0CXKrDf1_lKeGoiv
    upload ID: 5GuYO83ZlEkhPzApxM49nxvdpvNGF3AQkG0FZ..ALMMpoZGm8KaFBVZOf2qZWY3PGBRgDXZDZXUy_tiNNYeBUOpuUbIm_meupByUIZTdzy4CYkiy0CXKrDf1_lKeGoiv
    upload ID: 5GuYO83ZlEkhPzApxM49nxvdpvNGF3AQkG0FZ..ALMMpoZGm8KaFBVZOf2qZWY3PGBRgDXZDZXUy_tiNNYeBUOpuUbIm_meupByUIZTdzy4CYkiy0CXKrDf1_lKeGoiv
    part_info: {'Parts': [{'PartNumber': 1, 'ETag': '"3e3d3bae6867b8d207cae1974be3e"'}, {'PartNumber': 2, 'ETag': '"92720cb8294ee04961345f3b664d7"'}, {'PartNumber': 3, 'ETag': '"cc20868db2f8c8c4a6aa499340e0c"'}, {'PartNumber': 4, 'ETag': '"e1bee9034f163677e5ac917576dc7"'}, {'PartNumber': 5, 'ETag': '"b3cd45be65e828debf0d635e75a46"'}]}
    complete_rsp: {'ResponseMetadata': {'RequestId': 'B9TJF3EZZ8GSDV2V', 'HostId': 'g7r9/b1OQ8kPLoiDMlKbDREkoRapcDD+zsUJSf4NvlchxT2sS2xHxc42MyJO5ZlcAQ=', 'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amz-id-2': 'g7r9/b1OQ8kPLoiDMlKbqbE51X9iJDRapcDD+zsUJSf4NvlchxT2sS2xHxc42MyJO5ZlcAQ=', 'x-amz-request-id': 'B9TJF3EZZ8GSDV2V', 'date': 'Fri, 02 Jul 2021 15:23:08 GMT', 'content-type': 'application/xml', 'transfer-encoding': 'chunked', 'server': 'AmazonS3'}, 'RetryAttempts': 0}, 'Location': 'https://bucket-test.s3.cn-northwest-1.amazonaws.com.cn/static%2Fgopher.mp4', 'Bucket': 'bucket-test', 'Key': 'static/gopher.mp4', 'ETag': '"2b287762a4300abda18268e1151c83e9-5"'}
    """
    create_multipart_upload 参考链接:
     
    upload_part 参考链接:
     
    complete_multipart_upload 参考链接:
     
     
    Code your future.
  • 相关阅读:
    最短路
    P2863 [USACO06JAN]牛的舞会The Cow Prom
    牛客小白月赛12
    牛客练习赛41
    求余
    dreamstart 的催促
    deepin安装tesseract出错,tesserocr.cpp:653:10: fatal error: leptonica/allheaders.h: 没有那个文件或目录
    自动抽屉 + 点赞 + 取消赞
    爬取汽车之家
    css垂直居中和水平居中
  • 原文地址:https://www.cnblogs.com/neozheng/p/14965299.html
Copyright © 2020-2023  润新知