更新时间:2026-09-07 GMT+08:00
分享

分段复制

开发过程中,您有任何问题可以在GitHub上提交issue,或者在华为云对象存储服务论坛中发帖求助。接口参考文档详细介绍了每个接口的参数和使用方法。

分段复制是分段上传的一种特殊情况,即多段上传任务中的段通过复制OBS指定桶中现有对象(或对象的一部分)来实现。

您可以通过ObsClient->copyPart来复制段。

本示例用于分段复制桶 sourcebucketname 中的 对象 sourceobjectname 到桶 destbucketname 中的 对象 destobjectname。

代码示例如下所示:

<?php

// 引入依赖库
require 'vendor/autoload.php';
// 使用源码安装时引入SDK代码库
// require 'obs-autoloader.php';
// 声明命名空间
use Obs\ObsClient;
use Obs\ObsException;
use GuzzleHttp\Promise\Utils;
// 创建ObsClient实例
$obsClient = new ObsClient([
    //推荐通过环境变量获取访问密钥AK/SK,这里也可以使用其他外部引入方式传入,如果使用硬编码可能会存在泄露风险。
    //您可以登录访问管理控制台获取访问密钥AK/SK,获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.htmlhttps://support.huaweicloud.com/intl/zh-cn/usermanual-ca/ca_01_0003.htmlhttps://support.huaweicloud.com/eu/usermanual-ca/ca_01_0003.html
    'key' => getenv('ACCESS_KEY_ID'),
    'secret' => getenv('SECRET_ACCESS_KEY'),
    'endpoint' => 'https://your-endpoint',
]);$destBucketName = 'destbucketname';
$destObjectKey = 'destobjectname';
$sourceBucketName = 'sourcebucketname';
$sourceObjectKey = 'sourceobjectname';
// 初始化多段上传任务
$resp = $obsClient->initiateMultipartUpload([
    'Bucket' => $destBucketName,
    'Key' => $destObjectKey
]);
$uploadId = $resp['UploadId'];
printf( "UploadId:%s\n\n", $uploadId );
// 获取大对象信息
$resp = $obsClient->getObjectMetadata([
    'Bucket' => $sourceBucketName,
    'Key' => $sourceObjectKey
]);
// 每段复制100MB
$partSize = 100 * 1024 * 1024;
$objectSize = $resp['ContentLength'];
// 计算需要复制的段数
$partCount = $objectSize % $partSize === 0 ? intval ( $objectSize / $partSize ) : intval ( $objectSize / $partSize ) + 1;
// 执行并发复制段
$promises = [];
$parts = [];
for($i = 0; $i < $partCount; $i ++) {
    $rangeStart = $i * $partSize;
    $rangeEnd = ($i + 1 === $partCount) ? $objectSize - 1 : $rangeStart + $partSize - 1;
    $partNumber = $i + 1;
    $promises[] = $obsClient->copyPartAsync([
        'Bucket' => $destBucketName,
        'Key' => $destObjectKey,
        'UploadId' => $uploadId,
        'PartNumber' => $partNumber,
        'CopySource' => sprintf( '%s/%s', $sourceBucketName, $sourceObjectKey ),
        'CopySourceRange' => sprintf( 'bytes=%d-%d', $rangeStart, $rangeEnd )
    ], function ($exception, $resp) use (&$parts, $partNumber) {
        if ($exception !== null) {
            printf( "Part#" . strval ( $partNumber ) . " failed: " . $exception->getMessage () . "\n\n" );
            return;
        }
        $parts [] = [
            'PartNumber' => $partNumber,
            'ETag' => $resp['ETag']
        ];
        printf("Part#%d done\n\n", $partNumber);
    });
}
// 等待所有分段复制完成
Utils::all( $promises )->wait ();
usort ( $parts, function ($a, $b) {
    if ($a ['PartNumber'] === $b ['PartNumber']) {
        return 0;
    }
    return $a ['PartNumber'] > $b ['PartNumber'] ? 1 : - 1;
});
try {
    // 合并段
    $resp = $obsClient->completeMultipartUpload([
        'Bucket' => $destBucketName,
        'Key' => $destObjectKey,
        'UploadId' => $uploadId,
        'Parts' => $parts
    ]);;
  printf("Complete to upload multiparts finished, RequestId:%s\n", $resp['RequestId']);
} catch (ObsException $e) {
    // 操作失败,获取详细异常信息
    printf("InitiateMultipartUploadFailed: Status:%d, Code:%s, Message:%s\n", $e->getStatusCode(), $e->getExceptionCode(), $e->getExceptionMessage());
} finally {
    $obsClient->close();
}

复制段时,使用PartNumber参数指定分段号;使用UploadId参数指定多段上传任务的全局唯一标识;使用CopySource参数指定复制时的源对象信息;使用CopySourceRange参数指定待复制的源对象的字节范围。

相关文档