def resumable_download()

in oss2/resumable.py [0:0]


def resumable_download(bucket, key, filename,
                       multiget_threshold=None,
                       part_size=None,
                       progress_callback=None,
                       num_threads=None,
                       store=None,
                       params=None,
                       headers=None):
    """断点下载。

    实现的方法是:
        #. 在本地创建一个临时文件,文件名由原始文件名加上一个随机的后缀组成;
        #. 通过指定请求的 `Range` 头按照范围并发读取OSS文件,并写入到临时文件里对应的位置;
        #. 全部完成之后,把临时文件重命名为目标文件 (即 `filename` )

    在上述过程中,断点信息,即已经完成的范围,会保存在磁盘上。因为某种原因下载中断,后续如果下载
    同样的文件,也就是源文件和目标文件一样,就会先读取断点信息,然后只下载缺失的部分。

    缺省设置下,断点信息保存在 `HOME` 目录的一个子目录下。可以通过 `store` 参数更改保存位置。

    使用该函数应注意如下细节:
        #. 对同样的源文件、目标文件,避免多个程序(线程)同时调用该函数。因为断点信息会在磁盘上互相覆盖,或临时文件名会冲突。
        #. 避免使用太小的范围(分片),即 `part_size` 不宜过小,建议大于或等于 `oss2.defaults.multiget_part_size` 。
        #. 如果目标文件已经存在,那么该函数会覆盖此文件。
        #. 如果使用CryptoBucket,函数会退化为普通下载


    :param bucket: :class:`Bucket <oss2.Bucket>` 或者 ::class:`CryptoBucket <oss2.CryptoBucket>` 对象
    :param str key: 待下载的远程文件名。
    :param str filename: 本地的目标文件名。
    :param int multiget_threshold: 文件长度大于该值时,则使用断点下载。
    :param int part_size: 指定期望的分片大小,即每个请求获得的字节数,实际的分片大小可能有所不同。
    :param progress_callback: 下载进度回调函数。参见 :ref:`progress_callback` 。
    :param num_threads: 并发下载的线程数,如不指定则使用 `oss2.defaults.multiget_num_threads` 。

    :param store: 用来保存断点信息的持久存储,可以指定断点信息所在的目录。
    :type store: `ResumableDownloadStore`

    :param dict params: 指定下载参数,可以传入versionId下载指定版本文件

    :param headers: HTTP头部,
        # 调用外部函数head_object目前只传递OSS_REQUEST_PAYER
        # 调用外部函数get_object_to_file, get_object目前需要向下传递的值有OSS_REQUEST_PAYER, OSS_TRAFFIC_LIMIT
    :type headers: 可以是dict,建议是oss2.CaseInsensitiveDict

    :raises: 如果OSS文件不存在,则抛出 :class:`NotFound <oss2.exceptions.NotFound>` ;也有可能抛出其他因下载文件而产生的异常。
    """
    logger.debug("Start to resumable download, bucket: {0}, key: {1}, filename: {2}, multiget_threshold: {3}, "
                "part_size: {4}, num_threads: {5}".format(bucket.bucket_name, to_string(key), filename,
                                                          multiget_threshold, part_size, num_threads))
    multiget_threshold = defaults.get(multiget_threshold, defaults.multiget_threshold)

    valid_headers = _populate_valid_headers(headers, [OSS_REQUEST_PAYER, OSS_TRAFFIC_LIMIT])
    result = bucket.head_object(key, params=params, headers=valid_headers)
    logger.debug("The size of object to download is: {0}, multiget_threshold: {1}".format(result.content_length,
                                                                                          multiget_threshold))
    if result.content_length >= multiget_threshold:
        downloader = _ResumableDownloader(bucket, key, filename, _ObjectInfo.make(result), part_size=part_size,
                                          progress_callback=progress_callback, num_threads=num_threads, store=store,
                                          params=params, headers=valid_headers)
        downloader.download(result.server_crc)
    else:
        bucket.get_object_to_file(key, filename, progress_callback=progress_callback, params=params,
                                  headers=valid_headers)