拷貝檔案(Go SDK V1)
本文介紹如何在受版本控制的儲存空間(Bucket)中拷貝檔案(Object)。您可以通過CopyObject的方法拷貝小於1 GB的檔案,通過分區拷貝(UploadPartCopy)的方法拷貝大於1 GB的檔案。
注意事項
本文以華東1(杭州)外網Endpoint為例。如果您希望通過與OSS同地區的其他阿里雲產品訪問OSS,請使用內網Endpoint。關於OSS支援的Region與Endpoint的對應關係,請參見地區和Endpoint。
本文以從環境變數讀取存取憑證為例。如何配置訪問憑證,請參見配置訪問憑證(Go SDK V1)。
本文以OSS網域名稱建立OSSClient為例。如果您希望通過自訂網域名、STS等方式建立OSSClient,請參見配置用戶端(Go SDK V1)。
要拷貝檔案,您必須有
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自動產生唯一的versionId,此versionId將會在響應header的x-oss-version-id中返回。如果目標Bucket未曾開啟或者暫停了版本控制,OSS將會為新拷貝的Object自動產生versionId為”null“的版本,且會覆蓋原先versionId為”null“的版本。
目標Bucket在開啟或暫停版本控制狀態下,不支援對Appendable類型Object執行拷貝操作。
以下代碼用於拷貝小檔案:
package main
import (
"log"
"net/http"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func main() {
// 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
provider, err := oss.NewEnvironmentVariableCredentialsProvider()
if err != nil {
log.Fatalf("Failed to create credentials provider: %v", err)
}
// 建立OSSClient執行個體。
// yourEndpoint填寫Bucket對應的Endpoint,以華東1(杭州)為例,填寫為https://oss-cn-hangzhou.aliyuncs.com。其它Region請按實際情況填寫。
// yourRegion填寫Bucket所在地區,以華東1(杭州)為例,填寫為cn-hangzhou。其它Region請按實際情況填寫。
clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)}
clientOptions = append(clientOptions, oss.Region("yourRegion"))
// 設定簽名版本
clientOptions = append(clientOptions, oss.AuthVersion(oss.AuthV4))
client, err := oss.New("yourEndpoint", "", "", clientOptions...)
if err != nil {
log.Fatalf("Failed to create OSS client: %v", err)
}
// yourBucketName填寫儲存空間名稱。
bucketName := "yourBucketName"
// yourObjectName填寫不包含Bucket名稱在內的源Object的完整路徑。
objectName := "yourObjectName"
// yourDestObjectName填寫不包含Bucket名稱在內的目標Object的完整路徑。
destObjectName := "yourDestObjectName"
// 擷取Bucket執行個體。
bucket, err := client.Bucket(bucketName)
if err != nil {
log.Fatalf("Failed to get bucket '%s': %v", bucketName, err)
}
// 拷貝指定版本檔案到同一個儲存空間的另一個檔案,並擷取版本資訊。
var retHeader http.Header
_, err = bucket.CopyObject(objectName, destObjectName, oss.VersionId("yourObjectVersionId"), oss.GetResponseHeader(&retHeader))
if err != nil {
log.Fatalf("Failed to copy object '%s' to '%s': %v", objectName, destObjectName, err)
}
// 列印版本資訊。
versionId := oss.GetVersionId(retHeader)
copySourceVersionId := oss.GetCopySrcVersionId(retHeader)
log.Printf("x-oss-version-id: %s", versionId)
log.Printf("x-oss-copy-source-version-id: %s", copySourceVersionId)
}
拷貝大檔案
對於大於1GB的檔案,需要使用分區拷貝(UploadPartCopy)。
UploadPartCopy預設從一個已存在的Object的目前的版本中拷貝資料來上傳一個Part。允許通過在請求header : x-oss-copy-source中附帶versionId的子條件,實現從Object的指定版本進行拷貝,如x-oss-copy-source : /SourceBucketName/SourceObjectName?versionId=111111。
SourceObjectName要進行URL編碼。響應中將會返回被拷貝Object的版本id:x-oss-copy-source-version-id。
如果未指定versionId且拷貝Object的目前的版本為刪除標記,OSS將返回404 Not Found。通過指定versionId來拷貝刪除標記時,OSS將返回400 Bad Request。
以下代碼用於分區拷貝:
package main
import (
"log"
"net/http"
"time"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func main() {
// 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
provider, err := oss.NewEnvironmentVariableCredentialsProvider()
if err != nil {
log.Fatalf("Failed to create credentials provider: %v", err)
}
// 建立OSSClient執行個體。
// yourEndpoint填寫Bucket對應的Endpoint,以華東1(杭州)為例,填寫為https://oss-cn-hangzhou.aliyuncs.com。其它Region請按實際情況填寫。
// yourRegion填寫Bucket所在地區,以華東1(杭州)為例,填寫為cn-hangzhou。其它Region請按實際情況填寫。
clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)}
clientOptions = append(clientOptions, oss.Region("yourRegion"))
// 設定簽名版本
clientOptions = append(clientOptions, oss.AuthVersion(oss.AuthV4))
client, err := oss.New("yourEndpoint", "", "", clientOptions...)
if err != nil {
log.Fatalf("Failed to create OSS client: %v", err)
}
// yourBucketName填寫儲存空間名稱。
bucketName := "yourBucketName"
bucket, err := client.Bucket(bucketName)
if err != nil {
log.Fatalf("Failed to get bucket '%s': %v", bucketName, err)
}
// yourObjectName填寫不包含Bucket名稱在內的Object的完整路徑。
objectName := "yourObjectName"
fileName := "yourFileName"
futureDate := time.Date(2049, time.January, 10, 23, 0, 0, 0, time.UTC)
var retHeader http.Header
// 分割檔案。
chunks, err := oss.SplitFileByPartNum(fileName, 3)
if err != nil {
log.Fatalf("Failed to split file '%s': %v", fileName, err)
}
// 上傳一個待拷貝的大檔案。
err = bucket.PutObjectFromFile(objectName, fileName, oss.GetResponseHeader(&retHeader))
if err != nil {
log.Fatalf("Failed to put object '%s' from file '%s': %v", objectName, fileName, err)
}
// 取得上傳源檔案的versionId。
versionId := oss.GetVersionId(retHeader)
log.Printf("Source object version ID: %s", versionId)
// 設定拷貝檔案參數。
options := []oss.Option{
oss.Expires(futureDate),
oss.Meta("my", "myprop"),
}
// 目標檔案名。
objectDest := objectName + "dest"
var parts []oss.UploadPart
copyOptions := []oss.Option{
oss.VersionId(versionId),
oss.GetResponseHeader(&retHeader),
}
// 初始化一個分區上傳事件。
imu, err := bucket.InitiateMultipartUpload(objectDest, options...)
if err != nil {
log.Fatalf("Failed to initiate multipart upload for object '%s': %v", objectDest, err)
}
// 進行大檔案拷貝。
for _, chunk := range chunks {
part, err := bucket.UploadPartCopy(imu, bucketName, objectName, chunk.Offset, chunk.Size, int(chunk.Number), copyOptions...)
if err != nil {
log.Fatalf("Failed to upload part %d of object '%s': %v", chunk.Number, objectName, err)
}
parts = append(parts, part)
// 列印x-oss-copy-source-version-id。
log.Printf("x-oss-copy-source-version-id: %s", oss.GetCopySrcVersionId(retHeader))
}
// 完成分區上傳。
_, err = bucket.CompleteMultipartUpload(imu, parts, oss.GetResponseHeader(&retHeader))
if err != nil {
log.Fatalf("Failed to complete multipart upload for object '%s': %v", objectDest, err)
}
// 列印x-oss-version-id。
log.Printf("x-oss-version-id: %s", oss.GetVersionId(retHeader))
}
相關文檔
關於拷貝小檔案的API介面說明,請參見CopyObject。
關於拷貝大檔案的API介面說明,請參見UploadPartCopy。