拷贝Object是指在不改变文件内容的情况下,将同一地域下的源云盒Bucket内的文件复制到目标云盒Bucket,以实现数据备份、分发和灾难恢复。这有助于提高数据的可用性和冗余度,确保数据在不同Bucket之间的一致性和安全性。云盒是一种由阿里云提供的高效、可靠的数据存储和管理服务。目标Bucket应与源Bucket位于同一地域。
使用限制
不支持跨地域拷贝Object。例如,不支持将华东1(杭州)的Object拷贝到华东2(上海)。
不支持对通过追加上传方式生成的Object进行拷贝。
注意事项
您需要有源Object的读权限及目标Bucket的读写权限,否则无法完成拷贝操作。
拷贝文件时默认会覆盖同名文件。为防止文件被意外覆盖,您可以通过以下方式保护您的文件。
开启版本控制功能
被删除或覆盖的文件会以历史版本的形式保存下来,您可以随时恢复。更多信息,请参见版本控制。
在拷贝请求中携带禁止覆盖同名文件的参数
在拷贝请求的Header中携带 x-oss-forbid-overwrite参数,并指定其值为true。当您拷贝的文件在目标Bucket中存在同名文件时,该文件将拷贝失败,并返回
FileAlreadyExists
错误。
拷贝小文件
OSS ON云盒支持通过CopyObject接口拷贝小于1 GB的文件。
使用Java SDK
仅支持通过Java SDK拷贝文件,Java SDK要求3.15.0及以上版本。
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
public class Demo {
public static void main(String[] args) throws Exception {
// 填写云盒Bucket的数据域名。
String endpoint = "https://cb-f8z7yvzgwfkl9q0h****.cn-hangzhou.oss-cloudbox.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写源云盒Bucket与目标云盒Bucket所在地域。
String region = "cn-hangzhou";
// 填写云盒ID。
String cloudBoxId = "cb-f8z7yvzgwfkl9q0h****";
// 填写源云盒Bucket名称。
String sourceBucketName = "srcexamplebucket";
// 填写源Object的完整路径。Object完整路径中不能包含Bucket名称。
String sourceKey = "srcexampleobject.txt";
// 填写与源Bucket处于同一地域的目标云盒Bucket名称。
String destinationBucketName = "desexamplebucket";
// 填写目标Object的完整路径,完整路径中不能包含Bucket名称。
String destinationKey = "desexampleobject.txt";
// 创建OSSClient实例。
ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
conf.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(new DefaultCredentialProvider(credentialsProvider.getCredentials()))
.clientConfiguration(conf)
.region(region)
.cloudBoxId(cloudBoxId)
.build();
try {
// 创建CopyObjectRequest对象。
CopyObjectRequest copyObjectRequest = new CopyObjectRequest(sourceBucketName, sourceKey, destinationBucketName, destinationKey);
// 设置新的文件元数据。
ObjectMetadata meta = new ObjectMetadata();
meta.setContentType("text/txt");
// 指定CopyObject操作时是否覆盖同名目标Object。此处设置为true,表示禁止覆盖同名Object。
// meta.setHeader("x-oss-forbid-overwrite", "true");
// 指定拷贝的源地址。
// meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE, "/examplebucket/recode-test.txt");
// 如果源Object的ETag值和您提供的ETag相等,则执行拷贝操作,并返回200 OK。
// meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE_IF_MATCH, "5B3C1A2E053D763E1B002CC607C5****");
// 如果源Object的ETag值和您提供的ETag不相等,则执行拷贝操作,并返回200 OK。
// meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE_IF_NONE_MATCH, "5B3C1A2E053D763E1B002CC607C5****");
// 如果指定的时间等于或者晚于文件实际修改时间,则正常拷贝文件,并返回200 OK。
// meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE_IF_UNMODIFIED_SINCE, "2021-12-09T07:01:56.000Z");
// 如果源Object在指定时间后被修改过,则执行拷贝操作。
// meta.setHeader(OSSHeaders.COPY_OBJECT_SOURCE_IF_MODIFIED_SINCE, "2021-12-09T07:01:56.000Z");
// 指定设置目标Object元数据的方式。此处设置为COPY,表示复制源Object的元数据到目标Object。
// meta.setHeader(OSSHeaders.COPY_OBJECT_METADATA_DIRECTIVE, "COPY");
// 指定OSS创建目标Object时使用的服务器端加密算法。
// meta.setHeader(OSSHeaders.OSS_SERVER_SIDE_ENCRYPTION, ObjectMetadata.KMS_SERVER_SIDE_ENCRYPTION);
// 表示KMS托管的用户主密钥,该参数仅在x-oss-server-side-encryption为KMS时有效。
// meta.setHeader(OSSHeaders.OSS_SERVER_SIDE_ENCRYPTION_KEY_ID, "9468da86-3509-4f8d-a61e-6eab1eac****");
// 指定OSS创建目标Object时的访问权限,此处设置为Private,表示只有Object的拥有者和授权用户有该Object的读写权限,其他用户没有权限操作该Object。
// meta.setHeader(OSSHeaders.OSS_OBJECT_ACL, CannedAccessControlList.Private);
// 指定Object的存储类型。此处设置为Standard,表示标准存储类型。
// meta.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard);
// 指定Object的对象标签,可同时设置多个标签。
// meta.setHeader(OSSHeaders.OSS_TAGGING, "a:1");
// 指定设置目标Object对象标签的方式。此处设置为COPY,表示复制源Object的对象标签到目标Object。
// meta.setHeader(OSSHeaders.COPY_OBJECT_TAGGING_DIRECTIVE, "COPY");
copyObjectRequest.setNewObjectMetadata(meta);
// 复制文件。
CopyObjectResult result = ossClient.copyObject(copyObjectRequest);
System.out.println("ETag: " + result.getETag() + " LastModified: " + result.getLastModified());
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}
使用命令行管理工具ossutil
关于使用ossutil拷贝小文件的具体操作,请参见cp(拷贝文件)。
拷贝大文件
OSS ON云盒支持通过UploadPartCopy接口拷贝大于1 GB的文件。
使用Java SDK
仅支持通过Java SDK拷贝文件,Java SDK要求3.15.0及以上版本。
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import java.util.ArrayList;
import java.util.List;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
public class Demo {
public static void main(String[] args) throws Exception {
// 填写云盒Bucket的数据域名。
String endpoint = "https://cb-f8z7yvzgwfkl9q0h****.cn-hangzhou.oss-cloudbox.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写源云盒Bucket与目标云盒Bucket所在地域。
String region = "cn-hangzhou";
// 填写云盒ID。
String cloudBoxId = "cb-f8z7yvzgwfkl9q0h****";
// 填写源云盒Bucket名称。
String sourceBucketName = "srcexamplebucket";
// 填写源Object的完整路径。Object完整路径中不能包含Bucket名称。
String sourceKey = "srcexampleobject.txt";
// 填写与源Bucket处于同一地域的目标云盒Bucket名称。
String destinationBucketName = "desexamplebucket";
// 填写目标Object的完整路径。Object完整路径中不能包含Bucket名称。
String destinationKey = "desexampleobject.txt";
// 创建OSSClient实例。
ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
conf.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(new DefaultCredentialProvider(credentialsProvider.getCredentials()))
.clientConfiguration(conf)
.region(region)
.cloudBoxId(cloudBoxId)
.build();
try {
ObjectMetadata objectMetadata = ossClient.getObjectMetadata(sourceBucketName, sourceKey);
// 获取被拷贝文件的大小。
long contentLength = objectMetadata.getContentLength();
// 设置分片大小为10 MB。单位为字节。
long partSize = 1024 * 1024 * 10;
// 计算分片总数。
int partCount = (int) (contentLength / partSize);
if (contentLength % partSize != 0) {
partCount++;
}
System.out.println("total part count:" + partCount);
// 初始化拷贝任务。可以通过InitiateMultipartUploadRequest指定目标文件元数据。
InitiateMultipartUploadRequest initiateMultipartUploadRequest = new InitiateMultipartUploadRequest(destinationBucketName, destinationKey);
InitiateMultipartUploadResult initiateMultipartUploadResult = ossClient.initiateMultipartUpload(initiateMultipartUploadRequest);
String uploadId = initiateMultipartUploadResult.getUploadId();
// 分片拷贝。
List<PartETag> partETags = new ArrayList<PartETag>();
for (int i = 0; i < partCount; i++) {
// 计算每个分片的大小。
long skipBytes = partSize * i;
long size = partSize < contentLength - skipBytes ? partSize : contentLength - skipBytes;
// 创建UploadPartCopyRequest。可以通过UploadPartCopyRequest指定限定条件。
UploadPartCopyRequest uploadPartCopyRequest =
new UploadPartCopyRequest(sourceBucketName, sourceKey, destinationBucketName, destinationKey);
uploadPartCopyRequest.setUploadId(uploadId);
uploadPartCopyRequest.setPartSize(size);
uploadPartCopyRequest.setBeginIndex(skipBytes);
uploadPartCopyRequest.setPartNumber(i + 1);
UploadPartCopyResult uploadPartCopyResult = ossClient.uploadPartCopy(uploadPartCopyRequest);
// 将返回的分片ETag保存到partETags中。
partETags.add(uploadPartCopyResult.getPartETag());
}
// 提交分片拷贝任务。
CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(
destinationBucketName, destinationKey, uploadId, partETags);
ossClient.completeMultipartUpload(completeMultipartUploadRequest);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}
使用命令行管理工具ossutil
关于使用ossutil拷贝大文件的具体操作,请参见cp(拷贝文件)。
使用REST API
如果您的程序自定义要求较高,您可以直接发起REST API请求。直接发起REST API请求需要手动编写代码计算签名。更多信息,请参见UploadPartCopy。