Amazon S3 公用程式 - 適用於 Go 的 AWS SDK v2

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

Amazon S3 公用程式

Amazon S3 Transfer Manager

Amazon S3 上傳和下載管理員可以分解大型物件,因此可以多個部分平行傳輸。這可讓您輕鬆恢復中斷的傳輸。

Amazon S3 上傳管理員

Amazon S3 上傳管理員會判斷檔案是否可以分割成較小的部分並平行上傳。您可以自訂平行上傳的數量和上傳組件的大小。

下列範例使用 Amazon S3 Uploader上傳檔案。使用 Uploader 類似於 s3.PutObject()操作。

import "context" import "github.com/aws/aws-sdk-go-v2/config" import "github.com/aws/aws-sdk-go-v2/service/s3" import "github.com/aws/aws-sdk-go-v2/feature/s3/manager" // ... cfg, err := config.LoadDefaultConfig(context.TODO()) if err != nil { log.Printf("error: %v", err) return } client := s3.NewFromConfig(cfg) uploader := manager.NewUploader(client) result, err := uploader.Upload(context.TODO(), &s3.PutObjectInput{ Bucket: aws.String("amzn-s3-demo-bucket"), Key: aws.String("my-object-key"), Body: uploadFile, })

組態選項

當您使用 NewUploader 執行個體化Uploader執行個體時,您可以指定數個組態選項來自訂物件的上傳方式。選項是透過提供一或多個引數給 來覆寫NewUploader。這些選項包括:

  • PartSize – 指定要上傳的每個部分的緩衝區大小,以位元組為單位。每個組件的大小下限為 5 MiB。

  • Concurrency – 指定要平行上傳的組件數量。

  • LeavePartsOnError – 指出是否要在 Amazon S3 中保留成功上傳的組件。

Concurrency 值會限制指定Upload呼叫可能發生的並行部分上傳數目。這不是全域用戶端並行限制。調整 PartSizeConcurrency組態值以尋找最佳組態。例如,具有高頻寬連線的系統可以平行傳送較大的部分和更多上傳。

例如,您的應用程式Uploader使用 Concurrency的 設定 5。如果您的應用程式接著Upload從兩個不同的 goroutine 呼叫 ,則結果為10並行部分上傳 (2 個 goroutines * 5)Concurrency

警告

預期您的應用程式會將並行呼叫限制為 Upload,以防止應用程式資源耗盡。

以下是在Uploader建立期間設定預設組件大小的範例:

uploader := manager.NewUploader(client, func(u *Uploader) { u.PartSize = 10 * 1024 * 1024, // 10 MiB })

如需 Uploader及其組態的詳細資訊,請參閱 適用於 Go 的 AWS SDK API 參考中的上傳者

PutObjectInput 內文欄位 (io.ReadSeeker 與 io.Reader)

s3.PutObjectInput 結構的 Body 欄位是 io.Reader類型。不過,此欄位可以填入同時滿足 io.ReadSeekerio.ReaderAt 界面的類型,以改善主機環境的應用程式資源使用率。下列範例會建立滿足兩個界面ReadSeekerAt的類型:

type ReadSeekerAt interface { io.ReadSeeker io.ReaderAt }

對於 io.Reader類型,讀取器的位元組必須在記憶體中緩衝,才能上傳組件。當您增加 PartSizeConcurrency值時, 所需的記憶體 (RAM) 會大幅Uploader增加。所需的記憶體約為 PartSize * Concurrency。例如,為 指定 100 MB,為 PartSize 指定 10Concurrency, 至少需要 1 GB。

由於 io.Reader類型無法在讀取位元組之前判斷其大小,因此 Uploader無法計算上傳的組件數量。因此,如果您設定PartSize太低,大型檔案的 Amazon S3 上傳限制Uploader可以達到 10,000 個部分。如果您嘗試上傳超過 10,000 個組件,上傳會停止並傳回錯誤。

對於實作 ReadSeekerAt類型的body值, Uploader不會先緩衝記憶體中的內文內容,再將其傳送至 Amazon S3。 會在將檔案上傳至 Amazon S3 之前Uploader計算預期的組件數量。如果目前的 值PartSize需要超過 10,000 個組件才能上傳檔案, 會Uploader增加組件大小值,因此需要較少的組件。

處理失敗的上傳

如果上傳至 Amazon S3 的 依預設失敗, Uploader 會使用 Amazon S3 AbortMultipartUpload操作來移除上傳的部分。此功能可確保失敗的上傳不會使用 Amazon S3 儲存體。

您可以LeavePartsOnError設為 true,讓 Uploader不會刪除成功上傳的組件。這對於繼續部分完成的上傳非常有用。若要在上傳的組件上操作,您必須取得失敗上傳UploadID的 。下列範例示範如何使用manager.MultiUploadFailure錯誤界面類型來取得 UploadID

result, err := uploader.Upload(context.TODO(), &s3.PutObjectInput{ Bucket: aws.String("amzn-s3-demo-bucket"), Key: aws.String("my-object-key"), Body: uploadFile, }) output, err := u.upload(input) if err != nil { var mu manager.MultiUploadFailure if errors.As(err, &mu) { // Process error and its associated uploadID fmt.Println("Error:", mu) _ = mu.UploadID() // retrieve the associated UploadID } else { // Process error generically fmt.Println("Error:", err.Error()) } return }

每次上傳覆寫上傳者選項

您可以透過提供一或多個引數給 方法Upload來覆寫呼叫 時Uploader的選項。這些覆寫是並行安全的修改,不會影響持續上傳或後續Upload呼叫管理員。例如,若要覆寫特定上傳請求的PartSize組態:

params := &s3.PutObjectInput{ Bucket: aws.String("amzn-s3-demo-bucket"), Key: aws.String("my-key"), Body: myBody, } resp, err := uploader.Upload(context.TODO(), params, func(u *manager.Uploader) { u.PartSize = 10 * 1024 * 1024, // 10 MiB })

範例

將資料夾上傳至 Amazon S3

下列範例使用 path/filepath套件以遞迴方式收集檔案清單,並將其上傳至指定的 Amazon S3 儲存貯體。Amazon S3 物件的金鑰會以檔案的相對路徑做為字首。

package main import ( "context" "log" "os" "path/filepath" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/feature/s3/manager" "github.com/aws/aws-sdk-go-v2/service/s3" ) var ( localPath string bucket string prefix string ) func init() { if len(os.Args) != 4 { log.Fatalln("Usage:", os.Args[0], "<local path> <bucket> <prefix>") } localPath = os.Args[1] bucket = os.Args[2] prefix = os.Args[3] } func main() { walker := make(fileWalk) go func() { // Gather the files to upload by walking the path recursively if err := filepath.Walk(localPath, walker.Walk); err != nil { log.Fatalln("Walk failed:", err) } close(walker) }() cfg, err := config.LoadDefaultConfig(context.TODO()) if err != nil { log.Fatalln("error:", err) } // For each file found walking, upload it to Amazon S3 uploader := manager.NewUploader(s3.NewFromConfig(cfg)) for path := range walker { rel, err := filepath.Rel(localPath, path) if err != nil { log.Fatalln("Unable to get relative path:", path, err) } file, err := os.Open(path) if err != nil { log.Println("Failed opening file", path, err) continue } defer file.Close() result, err := uploader.Upload(context.TODO(), &s3.PutObjectInput{ Bucket: &bucket, Key: aws.String(filepath.Join(prefix, rel)), Body: file, }) if err != nil { log.Fatalln("Failed to upload", path, err) } log.Println("Uploaded", path, result.Location) } } type fileWalk chan string func (f fileWalk) Walk(path string, info os.FileInfo, err error) error { if err != nil { return err } if !info.IsDir() { f <- path } return nil }

下載管理員

Amazon S3 Downloader Manager 會判斷檔案是否可以分割成較小的部分並平行下載。您可以自訂平行下載的數量和下載組件的大小。

範例:下載檔案

下列範例使用 Amazon S3 Downloader下載檔案。使用 Downloader 類似於 s3.GetObject 操作。

import "context" import "github.com/aws/aws-sdk-go-v2/aws" import "github.com/aws/aws-sdk-go-v2/config" import "github.com/aws/aws-sdk-go-v2/service/s3" import "github.com/aws/aws-sdk-go-v2/feature/s3/manager" // ... cfg, err := config.LoadDefaultConfig(context.TODO()) if err != nil { log.Println("error:", err) return } client := s3.NewFromConfig(cfg) downloader := manager.NewDownloader(client) numBytes, err := downloader.Download(context.TODO(), downloadFile, &s3.GetObjectInput{ Bucket: aws.String("amzn-s3-demo-bucket"), Key: aws.String("my-key"), })

downloadFile 參數是 io.WriterAt類型。WriterAt 界面可讓 平行Downloader寫入檔案的多個部分。

組態選項

當您執行個體化Downloader執行個體時,您可以指定組態選項來自訂物件的下載方式:

  • PartSize – 指定要下載的每個部分的緩衝區大小,以位元組為單位。每個組件的大小下限為 5 MB。

  • Concurrency – 指定要平行下載的組件數目。

Concurrency 值會限制指定Download呼叫可同時執行的部分下載數量。這不是全域用戶端並行限制。調整 PartSizeConcurrency組態值以尋找最佳組態。例如,具有高頻寬連線的系統可以平行接收更大的部分和更多的下載。

例如,您的應用程式Downloader會使用 Concurrency的 來設定 5。然後,您的應用程式Download會從兩個不同的 goroutine 呼叫 ,結果將是10並行部分下載 (2 個 goroutines * 5)Concurrency

警告

預期您的應用程式會將並行呼叫限制為 Download,以防止應用程式資源耗盡。

如需 Downloader 及其其他組態選項的詳細資訊,請參閱 適用於 Go 的 AWS SDK API 參考中的 manager.Downloader

每次下載覆寫下載程式選項

您可以在呼叫 時Download,透過提供一或多個功能引數給 方法來覆寫Downloader選項。這些覆寫是並行安全修改,不會影響持續上傳或後續Download呼叫管理員。例如,若要覆寫特定上傳請求的PartSize組態:

params := &s3.GetObjectInput{ Bucket: aws.String("amzn-s3-demo-bucket"), Key: aws.String("my-key"), } resp, err := downloader.Download(context.TODO(), targetWriter, params, func(u *manager.Downloader) { u.PartSize = 10 * 1024 * 1024, // 10 MiB })
範例
下載儲存貯體中的所有物件

下列範例使用分頁從 Amazon S3 儲存貯體收集物件清單。然後,它會將每個物件下載到本機檔案。

package main import ( "context" "fmt" "log" "os" "path/filepath" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/feature/s3/manager" "github.com/aws/aws-sdk-go-v2/service/s3" ) var ( Bucket = "amzn-s3-demo-bucket" // Download from this bucket Prefix = "logs/" // Using this key prefix LocalDirectory = "s3logs" // Into this directory ) func main() { cfg, err := config.LoadDefaultConfig(context.TODO()) if err != nil { log.Fatalln("error:", err) } client := s3.NewFromConfig(cfg) manager := manager.NewDownloader(client) paginator := s3.NewListObjectsV2Paginator(client, &s3.ListObjectsV2Input{ Bucket: &Bucket, Prefix: &Prefix, }) for paginator.HasMorePages() { page, err := paginator.NextPage(context.TODO()) if err != nil { log.Fatalln("error:", err) } for _, obj := range page.Contents { if err := downloadToFile(manager, LocalDirectory, Bucket, aws.ToString(obj.Key)); err != nil { log.Fatalln("error:", err) } } } } func downloadToFile(downloader *manager.Downloader, targetDirectory, bucket, key string) error { // Create the directories in the path file := filepath.Join(targetDirectory, key) if err := os.MkdirAll(filepath.Dir(file), 0775); err != nil { return err } // Set up the local file fd, err := os.Create(file) if err != nil { return err } defer fd.Close() // Download the file using the AWS SDK for Go fmt.Printf("Downloading s3://%s/%s to %s...\n", bucket, key, file) _, err = downloader.Download(context.TODO(), fd, &s3.GetObjectInput{Bucket: &bucket, Key: &key}) return err }

GetBucketRegion

GetBucketRegion 是一種公用程式函數,用於判斷 Amazon S3 儲存貯 AWS 體的區域位置。 GetBucketRegion會取得 Amazon S3 用戶端,並使用它來判斷與用戶端設定區域相關聯之 AWS 分割區中請求的儲存貯體位置。

例如,若要尋找儲存貯體 的區域amzn-s3-demo-bucket

cfg, err := config.LoadDefaultConfig(context.TODO()) if err != nil { log.Println("error:", err) return } bucket := "amzn-s3-demo-bucket" region, err := manager.GetBucketRegion(ctx, s3.NewFromConfig(cfg), bucket) if err != nil { var bnf manager.BucketNotFound if errors.As(err, &bnf) { log.Printf("unable to find bucket %s's Region\n", bucket) } else { log.Println("error:", err) } return } fmt.Printf("Bucket %s is in %s region\n", bucket, region)

如果 GetBucketRegion 無法解析儲存貯體的位置,則 函數會傳回 BucketNotFound 錯誤類型,如範例所示。

不可查看的串流輸入

對於 PutObject和 等 API 操作UploadPart,Amazon S3 用戶端預期Body輸入參數的值預設會實作 io.Seeker 介面。用戶端使用io.Seeker界面來判斷要上傳的值長度,以及運算請求簽章的承載雜湊。如果Body輸入參數值未實作 io.Seeker,您的應用程式將收到錯誤。

operation error S3: PutObject, failed to compute payload hash: failed to seek body to start, request stream is not seekable

您可以使用中介軟體功能選項修改操作方法的 ,以變更此行為。WithAPIOptions 協助程式會傳回零或多個中介軟體變動器的功能選項。若要停用運算承載雜湊的用戶端並使用未簽署承載請求簽章,請新增 v4.SwapComputePayloadSHA256ForUnsignedPayloadMiddleware。

resp, err := client.PutObject(context.TODO(), &s3.PutObjectInput{ Bucket: &bucketName, Key: &objectName, Body: bytes.NewBuffer([]byte(`example object!`)), ContentLength: 15, // length of body }, s3.WithAPIOptions( v4.SwapComputePayloadSHA256ForUnsignedPayloadMiddleware, ))
警告

Amazon S3 要求為所有物件上傳至儲存貯體的內容長度提供。由於Body輸入參數未實作io.Seeker界面,用戶端將無法計算請求的 ContentLength 參數。參數必須由應用程式提供。如果未提供 ContentLength 參數,請求將會失敗。

將 SDK 的 Amazon S3 上傳管理員用於無法尋找且沒有已知長度的上傳。