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

分段复制

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

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

本示例用于分段复制桶名为“sourcebucketname”里的“sourceobjectname”对象到桶名为“destbucketname”里的“destobjectname”对象。

代码示例如下所示:

import android.util.Log;
import com.obs.services.ObsClient;
import com.obs.services.exception.ObsException;
import com.obs.services.model.CompleteMultipartUploadRequest;
import com.obs.services.model.CompleteMultipartUploadResult;
import com.obs.services.model.CopyPartRequest;
import com.obs.services.model.CopyPartResult;
import com.obs.services.model.InitiateMultipartUploadRequest;
import com.obs.services.model.InitiateMultipartUploadResult;
import com.obs.services.model.ObjectMetadata;
import com.obs.services.model.PartEtag;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class CopyPartDemo {
    private static final String TAG = "CopyPart";

    public void copyPart() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 认证用的ak和sk硬编码到代码中或者明文存储都有很大的安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全;本示例以ak和sk保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量ACCESS_KEY_ID和SECRET_ACCESS_KEY_ID。
                // 您可以登录访问管理控制台获取访问密钥AK/SK
                String ak = System.getenv("ACCESS_KEY_ID");
                String sk = System.getenv("SECRET_ACCESS_KEY_ID");
                // endpoint填写桶所在的endpoint,此处以华北-北京四为例,其他地区请按实际情况填写
                String endPoint = "https://your-endpoint";

                final String destBucketName = "destbucketname";
                final String destObjectKey = "destobjectname";
                final String sourceBucketName = "sourcebucketname";
                final String sourceObjectKey = "sourceobjectname";

                // 创建ObsClient实例
                final ObsClient obsClient = new ObsClient(ak, sk, endPoint);

                // 初始化线程池
                ExecutorService executorService = Executors.newFixedThreadPool(20);

                try {
                    // 初始化分段上传任务
                    InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(destBucketName, destObjectKey);
                    InitiateMultipartUploadResult result = obsClient.initiateMultipartUpload(request);

                    final String uploadId = result.getUploadId();
                    Log.i(TAG, "UploadId: " + uploadId);

                    // 获取源对象信息
                    ObjectMetadata metadata = obsClient.getObjectMetadata(sourceBucketName, sourceObjectKey);
                    // 每段复制100MB
                    long partSize = 100 * 1024 * 1024L;
                    long objectSize = metadata.getContentLength();

                    // 计算需要复制的段数
                    long partCount = objectSize % partSize == 0 ? objectSize / partSize : objectSize / partSize + 1;

                    final List<PartEtag> partEtags = Collections.synchronizedList(new ArrayList<PartEtag>());

                    // 执行并发复制段
                    for (int i = 0; i < partCount; i++) {
                        // 复制段起始位置
                        final long rangeStart = i * partSize;
                        // 复制段结束位置
                        final long rangeEnd = (i + 1 == partCount) ? objectSize - 1 : rangeStart + partSize - 1;
                        // 分段号
                        final int partNumber = i + 1;
                        executorService.execute(new Runnable() {
                            @Override
                            public void run() {
                                CopyPartRequest request = new CopyPartRequest();
                                request.setUploadId(uploadId);
                                request.setSourceBucketName(sourceBucketName);
                                request.setSourceObjectKey(sourceObjectKey);
                                request.setDestinationBucketName(destBucketName);
                                request.setDestinationObjectKey(destObjectKey);
                                request.setByteRangeStart(rangeStart);
                                request.setByteRangeEnd(rangeEnd);
                                request.setPartNumber(partNumber);
                                CopyPartResult result;
                                try {
                                    result = obsClient.copyPart(request);
                                    Log.i(TAG, "Part#" + partNumber + " done");
                                    partEtags.add(new PartEtag(result.getEtag(), result.getPartNumber()));
                                } catch (ObsException e) {
                                    Log.e(TAG, "Part#" + partNumber + " failed");
                                    Log.e(TAG, "HTTP Code:" + e.getResponseCode());
                                    Log.e(TAG, "Error Code:" + e.getErrorCode());
                                    Log.e(TAG, "Error Message:" + e.getErrorMessage());
                                    Log.e(TAG, "Request ID:" + e.getErrorRequestId());
                                    Log.e(TAG, "Host ID:" + e.getErrorHostId());
                                }
                            }
                        });
                    }

                    // 等待复制完成
                    executorService.shutdown();
                    while (!executorService.isTerminated()) {
                        try {
                            executorService.awaitTermination(5, TimeUnit.SECONDS);
                        } catch (InterruptedException e) {
                            Log.e(TAG, "awaitTermination interrupted: " + e.getMessage());
                        }
                    }

                    // 合并段
                    CompleteMultipartUploadRequest completeMultipartUploadRequest =
                        new CompleteMultipartUploadRequest(destBucketName, destObjectKey, uploadId, partEtags);
                    CompleteMultipartUploadResult completeResult = obsClient.completeMultipartUpload(completeMultipartUploadRequest);
                    Log.i(TAG, "CopyPart successfully, ETag: " + completeResult.getEtag());
                } catch (ObsException e) {
                    Log.e(TAG, "CopyPart failed");
                    Log.e(TAG, "HTTP Code:" + e.getResponseCode());
                    Log.e(TAG, "Error Code:" + e.getErrorCode());
                    Log.e(TAG, "Error Message:" + e.getErrorMessage());
                    Log.e(TAG, "Request ID:" + e.getErrorRequestId());
                    Log.e(TAG, "Host ID:" + e.getErrorHostId());
                } catch (Exception e) {
                    Log.e(TAG, "CopyPart failed: " + e.getMessage());
                    e.printStackTrace();
                } finally {
                    executorService.shutdownNow();
                    try {
                        obsClient.close();
                    } catch (Exception e) {
                        // 忽略关闭异常
                    }
                }
            }
        }).start();
    }
}

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

相关文档