拷贝文件
示例代码可以参考拷贝文件Demo
拷贝一个文件
用户可以通过copyObject方法拷贝一个Object,如下代码所示:
public void copyObject(BosClient client, String srcBucketName, String srcKey, String destBucketName, String destKey) {
// 拷贝Object
CopyObjectResponse copyObjectResponse = client.copyObject(srcBucketName, srcKey, destBucketName, destKey);
// 打印结果
System.out.println("ETag: " + copyObjectResponse.getETag() + " LastModified: " + copyObjectResponse.getLastModified());
}
copyObject 方法返回一个 CopyObjectResponse
对象,该对象中包含了新Object的ETag和修改时间。
通过CopyObjectRequest拷贝Object
用户也可以通过 CopyObjectRequest
实现Object的拷贝,如下代码所示:
// 初始化BosClient
BosClient client = ...;
// 创建CopyObjectRequest对象
CopyObjectRequest copyObjectRequest = new CopyObjectRequest(srcBucketName, srcKey, destBucketName, destKey);
// 设置新的Metadata
Map<String, String> userMetadata = new HashMap<String, String>();
userMetadata.put('<user-meta-key>','<user-meta-value>');
ObjectMetadata meta = new ObjectMetadata();
meta.setUserMetadata(userMetadata);
copyObjectRequest.setNewObjectMetadata(meta);
// 复制Object
CopyObjectResponse copyObjectResponse = client.copyObject(copyObjectRequest);
System.out.println("ETag: " + copyObjectResponse.getETag() + " LastModified: " + copyObjectResponse.getLastModified());
CopyObjectRequest
允许用户修改目的Object的ObjectMeta,同时也提供 MatchingETagConstraints
参数的设定。
设置Object的Copy属性
BOS同时会提供CopyObject接口用于将一个已经存在的Object拷贝到另外一个Object,拷贝过程中会对源Object的Etag或修改状态进行判断,根据判断结果决定是否执行拷贝。详细的参数解释如下:
名称 | 类型 | 描述 | 是否必需 |
---|---|---|---|
x-bce-copy-source-if-match | String | 如果源Object的ETag值和用户提供的ETag相等,则执行拷贝操作,否则拷贝失败。 | 否 |
x-bce-copy-source-if-none-match | String | 如果源Object的ETag和用户提供的ETag不相等,则执行拷贝操作,否则拷贝失败。 | 否 |
x-bce-copy-source-if-unmodified-since | String | 如果源object在x-bce-copy-source-if-unmodified-since之后没被修改,则执行拷贝操作,否则拷贝失败。 | 否 |
x-bce-copy-source-if-modified-since | String | 如果源object在x-bce-copy-source-if-modified-since之后被修改了,则执行拷贝操作,否则拷贝失败。 | 否 |
对应的示例代码:
// 初始化BosClient
BosClient client = ...;
// 创建CopyObjectRequest对象
CopyObjectRequest copyObjectRequest = new CopyObjectRequest(srcBucketName, srcKey, destBucketName, destKey);
// 设置新的Metadata
Map<String, String> userMetadata = new HashMap<String, String>();
userMetadata.put("<user-meta-key>","<user-meta-value>");
meta.setUserMetadata(userMetadata);
copyObjectRequest.setNewObjectMetadata(meta);
//copy-source-if-match
copyObjectRequest.withETag("111111111183bf192b57a4afc76fa632");
//copy-source-if-none-match
copyObjectRequest.withNoMatchingETagConstraint("111111111183bf192b57a4afc76fa632");
Date modifiedSinceConstraint = new Date();
SimpleDateFormat df = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z", Locale.UK);
df.setTimeZone(new java.util.SimpleTimeZone(0, "GMT"));
String date = df.format(modifiedSinceConstraint);
//copy-source-if-modified-since
copyObjectRequest.withModifiedSinceConstraint(date);
//copy-source-if-unmodified-since
copyObjectRequest.withUnmodifiedSinceConstraint(date);
// 复制Object
CopyObjectResponse copyObjectResponse = client.copyObject(copyObjectRequest);
System.out.println("ETag: " + copyObjectResponse.getETag() + " LastModified: " + copyObjectResponse.getLastModified());
同步Copy功能
当前BOS的CopyObject接口是通过同步方式实现的。同步方式下,BOS端会等待Copy实际完成才返回成功。同步Copy能帮助用户更准确的判断Copy状态,但用户感知的复制时间会变长,且复制时间和文件大小成正比。
同步Copy方式更符合业界常规,提升了与其它平台的兼容性。同步Copy方式还简化了BOS服务端的业务逻辑,提高了服务效率。
如果您使用bce-java-sdk-0.10.8版本之前的SDK,有可能会出现复制请求成功,但文件实际复制失败的情况,所以建议您使用最新版本SDK。
分块拷贝
除了通过CopyObject接⼝拷贝文件以外,BOS还提供了另外一种拷贝模式——Multipart Upload Copy。用户可以在如下的应用场景内(但不仅限于此),使用Multipart Upload Copy,如:
- 需要支持断点拷贝。
- 拷贝超过5GB大小的文件。
- 网络条件较差,和BOS的服务器之间的连接经常断开。
下面将介绍分步实现三步拷贝。
三步拷贝包含init、“拷贝分块”和complete三步,其中init和complete的操作同分块上传一致。
为了便于理解,下面提供三步拷贝完整代码:
// 第一步 init
InitiateMultipartUploadRequest initiateMultipartUploadRequest =
new InitiateMultipartUploadRequest("targetBucketName","targetObjectName");
InitiateMultipartUploadResponse initiateMultipartUploadResponse =
client.initiateMultipartUpload(initiateMultipartUploadRequest);
// 第二步 分块拷贝
long left_size=client.getObjectMetadata("sourceBucketName","sourceObjectName").getContentLength();
long skipBytes = 0;
int partNumber = 1;
List<PartETag> partETags = new ArrayList<PartETag>();
while (left_size > 0) {
long partSize = 1024 * 1024 * 1L;
if (left_size < partSize) {
partSize = left_size;
}
UploadPartCopyRequest uploadPartCopyRequest = new UploadPartCopyRequest();
uploadPartCopyRequest.setBucketName("targetBucketName");
uploadPartCopyRequest.setKey("targetObjectName");
uploadPartCopyRequest.setSourceBucketName("sourceBucketName");
uploadPartCopyRequest.setSourceKey("sourceObjectName");
uploadPartCopyRequest.setUploadId(initiateMultipartUploadResponse.getUploadId());
uploadPartCopyRequest.setPartSize(partSize);
uploadPartCopyRequest.setOffSet(skipBytes);
uploadPartCopyRequest.setPartNumber(partNumber);
UploadPartCopyResponse uploadPartCopyResponse = client.uploadPartCopy(uploadPartCopyRequest);
// 将返回的PartETag保存到List中
PartETag partETag = new PartETag(partNumber,uploadPartCopyResponse.getETag());
partETags.add(partETag);
left_size -= partSize;
skipBytes += partSize;
partNumber+=1;
}
// 第三步 complete
CompleteMultipartUploadRequest completeMultipartUploadRequest =
new CompleteMultipartUploadRequest("targetBucketName", "targetObjectName", initiateMultipartUploadResponse.getUploadId(), partETags);
CompleteMultipartUploadResponse completeMultipartUploadResponse =
client.completeMultipartUpload(completeMultipartUploadRequest);
注意:
- offset参数以字节为单位,为分块的开始偏移位置。
- size参数以字节为单位,定义每个分块的大小,除最后一个Part以外,其他的Part大小都要大于 5MB。