You need to enable JavaScript to run this app.
导航

范围下载(PHP SDK)

最近更新时间2024.02.04 18:30:59

首次发布时间2022.11.16 14:58:44

范围下载可用于下载对象中的部分数据,可使用该特性实现大对象下载,其原理是将原始对象切分成多个分片分别依次下载,并在目标侧(例如本地文件系统)生成完整的数据。

注意事项

按照 HTTP 的 Range 请求头域规范,范围下载时指定的范围区间满足从 0 开始的左闭右闭规则,例如 bytes=0-1,代表下载对象的第一个字节和第二个字节,总共两个字节。

示例代码

范围下载的示例代码如下:

<?php

// 假设使用 composer 安装
require_once __DIR__ . '/vendor/autoload.php';

use Tos\TosClient;
use Tos\Exception\TosClientException;
use Tos\Exception\TosServerException;
use Tos\Model\HeadObjectInput;
use Tos\Model\GetObjectInput;

$file = null;
$output = null;
try {
    $client = new TosClient([
        'region' => 'your region',
        'endpoint' => 'your endpoint',
        // 从环境变量中获取访问密钥
        'ak' => getenv('TOS_ACCESS_KEY'),
        'sk' => getenv('TOS_SECRET_KEY'),
    ]);

    // 获取对象元数据
    $headObjectOutput = $client->headObject(new HeadObjectInput('bucket-test', 'key-test'));
    echo $headObjectOutput->getRequestId() . PHP_EOL;

    // 假设按照 20MB 切分大文件
    $partSize = intval(5 * 1024 * 1024);
    // 通过对象大小切分下载的范围
    $objectSize = $headObjectOutput->getContentLength();
    $partCount = intval($objectSize / $partSize);
    if ($objectSize % $partSize !== 0) {
        $partCount++;
    }

    // 假设下载到本地大文件路径为 local_big_file_path
    $localBigFilePath = 'local_big_file_path';

    $file = fopen($localBigFilePath, 'w');
    // 通过范围下载依次下载每个分片,并写入本地文件
    for ($i = 0; $i < $partCount; $i++) {
        $input = new GetObjectInput('bucket-test', 'key-test');
        // 设置下载对象的起始位置
        $input->setRangeStart($i * $partSize);
        // 注意 RangeEnd 的取值区间
        if ($i === $partCount - 1) {
            // 处理最后一个分片
            $input->setRangeEnd($objectSize - 1);
        } else {
            $input->setRangeEnd(($i + 1) * $partSize - 1);
        }
        // 设置写入本地文件的起始位置,一般同 RangeStart
        fseek($file, $partSize * $i, 0);
        $output = $client->getObject($input);
        echo $headObjectOutput->getRequestId() . PHP_EOL;

        while ($buf = $output->getContent()->read(65536)) {
            fwrite($file, $buf, strlen($buf));
        }
        $output->getContent()->close();
        echo sprintf('get object by range %d succeed', $i) . PHP_EOL;
    }
} catch (TosClientException $ex) {
    echo $ex->getMessage() . PHP_EOL;
} catch (TosServerException $ex) {
    echo $ex->getRequestId() . PHP_EOL;
    echo $ex->getStatusCode() . PHP_EOL;
    echo $ex->getErrorCode() . PHP_EOL;
} finally {
    if (is_resource($file)) {
        fclose($file);
    }

    if ($output) {
        $output->getContent()->close();
    }
}