更新时间: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参数指定待复制的源对象的字节范围。
父主题: 多段操作