本文介紹如何在受版本控制的儲存空間(Bucket)中拷貝檔案(Object)。您可以通過CopyObject的方法拷貝小於1 GB的檔案,通過分區拷貝(UploadPartCopy)的方法拷貝大於1 GB的檔案。
注意事項
本文以華東1(杭州)外網Endpoint為例。如果您希望通過與OSS同地區的其他阿里雲產品訪問OSS,請使用內網Endpoint。關於OSS支援的Region與Endpoint的對應關係,請參見地區和Endpoint。
本文以OSS網域名稱建立OSSClient為例。如果您希望通過自訂網域名、STS等方式建立OSSClient,請參見建立OssClient。
要拷貝檔案,您必須有
oss:GetObject和oss:PutObject許可權。具體操作,請參見為RAM使用者授予自訂的權限原則。
拷貝小檔案
對於小於1 GB的檔案,您可以通過CopyObject方法將檔案從一個儲存空間(源儲存空間)複製到同一地區的另一個儲存空間(目標儲存空間)。
x-oss-copy-source預設拷貝Object的目前的版本。如果目前的版本是刪除標記,則返回404表示該Object不存在。您可以在x-oss-copy-source中加入versionId來拷貝指定的Object版本,刪除標記不能被拷貝。
您可以將Object的早期版本拷貝到同一個Bucket中,拷貝Object的歷史版本將會成為一個新的目前的版本,達到恢複Object早期版本的目的。
如果目標Bucket已開啟版本控制,OSS將會為新拷貝出來的Object自動產生唯一的版本ID,此版本ID將會在響應header 的x-oss-version-id中返回。如果目標Bucket未曾開啟或者暫停了版本控制,OSS將會為新拷貝的Object自動產生version ID為”null“的版本,且會覆蓋原先versionId為”null“的版本。
目標Bucket在開啟或暫停版本控制狀態下,不支援對Appendable類型Object執行拷貝操作。
以下代碼用於拷貝小檔案:
#include <alibabacloud/oss/OssClient.h>
using namespace AlibabaCloud::OSS;
int main(void)
{
/* 初始化OSS帳號資訊。*/
/* yourEndpoint填寫Bucket所在地區對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。*/
std::string Endpoint = "yourEndpoint";
/* yourRegion填寫Bucket所在地區對應的Region。以華東1(杭州)為例,Region填寫為cn-hangzhou。*/
std::string Region = "yourRegion";
/* 填寫源Bucket名稱,例如srcexamplebucket。*/
std::string SourceBucketName = "srcexamplebucket";
/* 填寫與源Bucket處於同一地區的目標Bucket名稱,例如destbucket。*/
std::string CopyBucketName = "destbucket";
/* 填寫源Object的完整路徑,完整路徑中不能包含Bucket名稱,例如srcdir/scrobject.txt。*/
std::string SourceObjectName = "srcdir/scrobject.txt";
/* 填寫目標Object的完整路徑,完整路徑中不能包含Bucket名稱,例如destdir/destobject.txt。*/
std::string CopyObjectName = "destdir/destobject.txt";
/* 初始化網路等資源。*/
InitializeSdk();
ClientConfiguration conf;
conf.signatureVersion = SignatureVersionType::V4;
/* 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/
auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>();
OssClient client(Endpoint, credentialsProvider, conf);
client.SetRegion(Region);
CopyObjectRequest request(CopyBucketName, CopyObjectName);
request.setCopySource(SourceBucketName, SourceObjectName);
/* 填寫源Object的版本ID。*/
request.setVersionId("yourSourceObjectVersionId");
/* 拷貝指定版本的Object。*/
auto outcome = client.CopyObject(request);
if (outcome.isSuccess()) {
std::cout << "versionid:" << outcome.result().VersionId() << std::endl;
}
else {
/* 異常處理。*/
std::cout << "CopyObject fail" <<
",code:" << outcome.error().Code() <<
",message:" << outcome.error().Message() <<
",requestId:" << outcome.error().RequestId() << std::endl;
return -1;
}
/* 釋放網路等資源。*/
ShutdownSdk();
return 0;
}拷貝大檔案
對於大於1 GB的檔案,需要使用分區拷貝(UploadPartCopy)。
UploadPartCopy預設從一個已存在的Object的目前的版本中拷貝資料來上傳一個Part。允許通過在請求header : x-oss-copy-source中附帶versionId的子條件,實現從Object的指定版本進行拷貝,例如x-oss-copy-source : /SourceBucketName/SourceObjectName?versionId=CAEQMxiBgICAof2D0BYiIDJhMGE3N2M1YTI1NDQzOGY5NTkyNTI3MGYyMzJm****。
SourceObjectName要進行URL編碼。響應中將會返回被拷貝的Object版本ID,即x-oss-copy-source-version-id。
如果未指定versionId且拷貝Object的目前的版本為刪除標記,OSS將返回404 Not Found。通過指定versionId來拷貝刪除標記時,OSS將返回400 Bad Request。
以下代碼用於分區拷貝:
#include <alibabacloud/oss/OssClient.h>
#include <sstream>
using namespace AlibabaCloud::OSS;
int main(void)
{
/* 初始化OSS帳號資訊。*/
/* yourEndpoint填寫Bucket所在地區對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。*/
std::string Endpoint = "yourEndpoint";
/* yourRegion填寫Bucket所在地區對應的Region。以華東1(杭州)為例,Region填寫為cn-hangzhou。*/
std::string Region = "yourRegion";
/* 填寫源Bucket名稱,例如srcexamplebucket。*/
std::string SourceBucketName = "srcexamplebucket";
/* 填寫與源Bucket處於同一地區的目標Bucket名稱,例如destbucket。*/
std::string CopyBucketName = "destbucket";
/* 填寫源Object的完整路徑,完整路徑中不能包含Bucket名稱,例如srcdir/scrobject.txt。*/
std::string SourceObjectName = "srcdir/scrobject.txt";
/* 填寫目標Object的完整路徑,完整路徑中不能包含Bucket名稱,例如destdir/destobject.txt。*/
std::string CopyObjectName = "destdir/destobject.txt";
/* 初始化網路等資源。*/
InitializeSdk();
ClientConfiguration conf;
conf.signatureVersion = SignatureVersionType::V4;
/* 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/
auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>();
OssClient client(Endpoint, credentialsProvider, conf);
client.SetRegion(Region);
auto getObjectMetaReq = GetObjectMetaRequest(SourceBucketName, SourceObjectName);
/* 填寫源Object的版本ID。*/
getObjectMetaReq.setVersionId("yourSourceObjectVersionId");
auto getObjectMetaResult = client.GetObjectMeta(getObjectMetaReq);
if (!getObjectMetaResult.isSuccess()) {
std::cout << "GetObjectMeta fail" <<
",code:" << getObjectMetaResult.error().Code() <<
",message:" << getObjectMetaResult.error().Message() <<
",requestId:" << getObjectMetaResult.error().RequestId() << std::endl;
return -1;
}
/* 擷取被拷貝檔案大小。*/
auto objectSize = getObjectMetaResult.result().ContentLength();
/* 拷貝大檔案。*/
InitiateMultipartUploadRequest initUploadRequest(CopyBucketName, CopyObjectName);
/* 初始化分區拷貝事件。*/
auto uploadIdResult = client.InitiateMultipartUpload(initUploadRequest);
auto uploadId = uploadIdResult.result().UploadId();
int64_t partSize = 100 * 1024;
PartList partETagList;
int partCount = static_cast<int>(objectSize / partSize);
/* 計算分區個數。*/
if (objectSize % partSize != 0) {
partCount++;
}
/* 對每一個分區進行拷貝。*/
for (int i = 1; i <= partCount; i++) {
auto skipBytes = partSize * (i - 1);
auto size = (partSize < objectSize - skipBytes) ? partSize : (objectSize - skipBytes);
auto uploadPartCopyReq = UploadPartCopyRequest(CopyBucketName, CopyObjectName, SourceBucketName, SourceObjectName,uploadId, i);
uploadPartCopyReq.setCopySourceRange(skipBytes, skipBytes + size -1);
/* 填寫源Object的版本ID。*/
uploadPartCopyReq.setVersionId("yourSourceObjectVersionId");
auto uploadPartOutcome = client.UploadPartCopy(uploadPartCopyReq);
if (uploadPartOutcome.isSuccess()) {
Part part(i, uploadPartOutcome.result().ETag());
partETagList.push_back(part);
}
else {
std::cout << "UploadPartCopy fail" <<
",code:" << uploadPartOutcome.error().Code() <<
",message:" << uploadPartOutcome.error().Message() <<
",requestId:" << uploadPartOutcome.error().RequestId() << std::endl;
}
}
/* 完成分區拷貝。*/
CompleteMultipartUploadRequest request(CopyBucketName, CopyObjectName, partETagList, uploadId);
auto outcome = client.CompleteMultipartUpload(request);
if (outcome.isSuccess()) {
std::cout << "versionid:" << outcome.result().VersionId() << std::endl;
}
else {
/* 異常處理。*/
std::cout << "CompleteMultipartUpload fail" <<
",code:" << outcome.error().Code() <<
",message:" << outcome.error().Message() <<
",requestId:" << outcome.error().RequestId() << std::endl;
return -1;
}
/* 釋放網路等資源。*/
ShutdownSdk();
return 0;
}相關文檔
關於拷貝小檔案的API介面說明,請參見CopyObject。
關於拷貝大檔案的API介面說明,請參見UploadPartCopy。