本文介绍如何将源Bucket中的文件(Object)复制到同一地域下相同或不同目标Bucket中。
注意事项
- 本文以华东1(杭州)外网Endpoint为例。如果您希望通过与OSS同地域的其他阿里云产品访问OSS,请使用内网Endpoint。关于OSS支持的Region与Endpoint的对应关系,请参见访问域名和数据中心。
-
本文以从环境变量读取访问凭证为例。如何配置访问凭证,请参见Java配置访问凭证。
- 本文以OSS域名新建OSSClient为例。如果您希望通过自定义域名、STS等方式新建OSSClient,请参见新建OSSClient。
-
拷贝文件时,您必须拥有源文件的读权限及目标Bucket的读写权限。
-
拷贝文件时,您需要确保源Bucket和目标Bucket均未设置合规保留策略,否则报错The object you specified is immutable.。
-
不支持跨地域拷贝。例如不能将华东1(杭州)地域存储空间中的文件拷贝到华北1(青岛)地域。
拷贝小文件
对于小于1 GB的文件,您可以通过ossClient.copyObject方法拷贝文件。此方法有两种参数指定方式:
参数指定方式 |
描述 |
CopyObjectResult copyObject(String sourceBucketName, String sourceKey, String destinationBucketName, String destinationKey) |
允许指定源存储空间和源文件,以及目标存储空间和目标文件。拷贝后,目标文件的内容及元信息与源文件相同,称为简单拷贝。 |
CopyObjectResult copyObject(CopyObjectRequest copyObjectRequest) |
允许指定目标文件的元信息和拷贝的限制条件。如果拷贝操作的源文件地址和目标文件地址相同,则直接替换源文件的元信息。 |
CopyObjectRequest可设置的参数请参见下表。
参数 |
描述 |
方法 |
sourceBucketName |
源存储空间名称。 |
setSourceBucketName(String sourceBucketName) |
sourceKey |
源文件名称。 |
setSourceKey(String sourceKey) |
destinationBucketName |
目标存储空间名称。 |
setDestinationBucketName(String destinationBucketName) |
destinationKey |
目标文件名称。 |
setDestinationKey(String destinationKey) |
newObjectMetadata |
目标文件元信息。 |
setNewObjectMetadata(ObjectMetadata newObjectMetadata) |
matchingETagConstraints |
拷贝的限制条件。如果源文件的ETag值和用户提供的ETag值相等,则执行拷贝操作,否则返回错误。 |
setMatchingETagConstraints(List matchingETagConstraints) |
nonmatchingEtagConstraints |
拷贝的限制条件。如果源文件的ETag值和用户提供的ETag值不相等,则执行拷贝操作,否则返回错误。 |
setNonmatchingETagConstraints(List nonmatchingEtagConstraints) |
unmodifiedSinceConstraint |
拷贝的限制条件。如果传入参数中的时间等于或者晚于文件实际修改时间,则执行拷贝操作,否则返回错误。 |
setUnmodifiedSinceConstraint(Date unmodifiedSinceConstraint) |
modifiedSinceConstraint |
拷贝的限制条件。如果源文件在指定的时间之后被修改过,则执行拷贝操作,否则返回错误。 |
setModifiedSinceConstraint(Date modifiedSinceConstraint) |
CopyObjectResult的参数说明请参见下表。
参数 |
描述 |
方法 |
etag |
OSS文件唯一性标识。 |
String getETag() |
lastModified |
文件最后修改时间。 |
Date getLastModified() |
拷贝小文件有以下几种拷贝形式。
-
简单拷贝
以下代码用于通过简单拷贝将srcexamplebucket中的srcexampleobject.txt文件拷贝到目标存储空间desexamplebucket中的desexampleobject.txt文件。
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.*; public class Demo { public static void main(String[] args) throws Exception { // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。 String endpoint = "https://oss-cn-hangzhou.aliyuncs.com"; // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // 填写源Bucket名称。 String sourceBucketName = "srcexamplebucket"; // 填写源Object的完整路径,完整路径中不能包含Bucket名称。 String sourceKey = "srcexampleobject.txt"; // 填写与源Bucket处于同一地域的目标Bucket名称。 String destinationBucketName = "desexamplebucket"; // 填写目标Object的完整路径。Object完整路径中不能包含Bucket名称。 String destinationKey = "desexampleobject.txt"; // 创建OSSClient实例。 OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider); try { // 拷贝文件。 CopyObjectResult result = ossClient.copyObject(sourceBucketName, sourceKey, destinationBucketName, destinationKey); 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(); } } } }
-
通过CopyObjectRequest拷贝
以下代码用于通过CopyObjectRequest将srcexamplebucket中的srcexampleobject.txt文件拷贝到目标存储空间desexamplebucket中的desexampleobject.txt文件。
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.*; public class Demo { public static void main(String[] args) throws Exception { // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。 String endpoint = "https://oss-cn-hangzhou.aliyuncs.com"; // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider(); // 填写源Bucket名称。 String sourceBucketName = "srcexamplebucket"; // 填写源Object的完整路径。Object完整路径中不能包含Bucket名称。 String sourceKey = "srcexampleobject.txt"; // 填写与源Bucket处于同一地域的目标Bucket名称。 String destinationBucketName = "desexamplebucket"; // 填写目标Object的完整路径。Object完整路径中不能包含Bucket名称。 String destinationKey = "desexampleobject.txt"; // 创建OSSClient实例。 OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider); try { // 创建CopyObjectRequest对象。 CopyObjectRequest copyObjectRequest = new CopyObjectRequest(sourceBucketName, sourceKey, destinationBucketName, destinationKey); // 设置新的文件元信息。 ObjectMetadata meta = new ObjectMetadata(); meta.setContentType("text/plain"); // 指定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(); } } } }
拷贝大文件
对于大于1 GB的文件,需要使用分片拷贝(UploadPartCopy)。分片拷贝分为三步:
-
通过ossClient.initiateMultipartUpload初始化分片拷贝任务。
-
通过ossClient.uploadPartCopy进行分片拷贝。除最后一个分片外,其它分片都要大于100KB。
-
通过ossClient.completeMultipartUpload提交分片拷贝任务。
以下代码用于通过分片拷贝将srcexamplebucket中的srcexampleobject.txt文件拷贝到目标存储空间desexamplebucket中的desexampleobject.txt文件。
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;
public class Demo {
public static void main(String[] args) throws Exception {
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写源Bucket名称。
String sourceBucketName = "srcexamplebucket";
// 填写源Object的完整路径。Object完整路径中不能包含Bucket名称。
String sourceKey = "srcexampleobject.txt";
// 填写与源Bucket处于同一地域的目标Bucket名称。
String destinationBucketName = "desexamplebucket";
// 填写目标Object的完整路径。Object完整路径中不能包含Bucket名称。
String destinationKey = "desexampleobject.txt";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
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);
// 拷贝源文件ContentType和UserMetadata,分片拷贝默认不拷贝源文件的ContentType和UserMetadata。
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType(objectMetadata.getContentType());
metadata.setUserMetadata(objectMetadata.getUserMetadata());
initiateMultipartUploadRequest.setObjectMetadata(metadata);
InitiateMultipartUploadResult initiateMultipartUploadResult = ossClient.initiateMultipartUpload(initiateMultipartUploadRequest);
String uploadId = initiateMultipartUploadResult.getUploadId();
// 分片拷贝。
List partETags = new ArrayList();
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);
//Map headers = new HashMap();
// 指定拷贝的源地址。
// headers.put(OSSHeaders.COPY_OBJECT_SOURCE, "/examplebucket/desexampleobject.txt");
// 指定源Object的拷贝范围。例如设置bytes=0~1023,表示拷贝1~1024字节的内容。
// headers.put(OSSHeaders.COPY_SOURCE_RANGE, "bytes=0~1023");
// 如果源Object的ETag值和您提供的ETag相等,则执行拷贝操作,并返回200 OK。
// headers.put(OSSHeaders.COPY_OBJECT_SOURCE_IF_MATCH, "5B3C1A2E053D763E1B002CC607C5****");
// 如果源Object的ETag值和您提供的ETag不相等,则执行拷贝操作,并返回200 OK。
// headers.put(OSSHeaders.COPY_OBJECT_SOURCE_IF_NONE_MATCH, "5B3C1A2E053D763E1B002CC607C5****");
// 如果指定的时间等于或者晚于文件实际修改时间,则正常拷贝文件,并返回200 OK。
// headers.put(OSSHeaders.COPY_OBJECT_SOURCE_IF_UNMODIFIED_SINCE, "2021-12-09T07:01:56.000Z");
// 如果源Object在用户指定的时间以后被修改过,则执行拷贝操作。
// headers.put(OSSHeaders.COPY_OBJECT_SOURCE_IF_MODIFIED_SINCE, "2021-12-09T07:01:56.000Z");
// uploadPartCopyRequest.setHeaders(headers);
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();
}
}
}
}
相关文档
-
拷贝小文件
关于拷贝小文件的API接口说明,请参见CopyObject。
-
拷贝大文件
-
关于拷贝大文件的完整示例代码,请参见GitHub示例。
-
关于拷贝大文件的API接口说明,请参见UploadPartCopy。
-
内容没看懂? 不太想学习?想快速解决? 有偿解决: 联系专家
阿里云企业补贴进行中: 马上申请
腾讯云限时活动1折起,即将结束: 马上收藏
同尘科技为腾讯云授权服务中心。
购买腾讯云产品享受折上折,更有现金返利:同意关联,立享优惠
转转请注明出处:https://www.yunxiaoer.com/158037.html