View a markdown version of this page

Utilitários do Amazon S3 - AWS SDK para Go v2

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Utilitários do Amazon S3

Gerenciadores de transferências do Amazon S3

Os gerenciadores de upload e download do Amazon S3 podem dividir objetos grandes, para que possam ser transferidos em várias partes, paralelamente. Isso facilita a retomada de transferências interrompidas.

Gerenciador de uploads do Amazon S3

O gerenciador de uploads do Amazon S3 determina se um arquivo pode ser dividido em partes menores e carregado paralelamente. Você pode personalizar o número de uploads paralelos e o tamanho das partes enviadas.

O seguinte exemplo usa o Uploader do Amazon S3 para fazer upload de um arquivo. O uso de Uploader é semelhante à operação 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, })

Opções de configuração

Ao instanciar uma Uploader instância usando NewUploader, você pode especificar várias opções de configuração para personalizar como os objetos são carregados. As opções são substituídas fornecendo um ou mais argumentos para NewUploader. Essas opções incluem:

  • PartSize: especifica o tamanho do buffer, em bytes, de cada parte a ser carregada. O tamanho mínimo por parte é de 5 MiB.

  • Concurrency: especifica o número exato de partes a serem carregadas em paralelo.

  • LeavePartsOnError: indica se as partes carregadas com sucesso devem ser deixadas no Amazon S3.

O valor de Concurrency limita o número simultâneo de uploads de partes que podem ocorrer em determinada chamada de Upload. Esse não é um limite global de simultaneidade de clientes. Ajuste os valores de configuração PartSize e Concurrency para encontrar a configuração ideal. Por exemplo, sistemas com conexões de alta largura de banda podem enviar partes maiores e mais uploads em paralelo.

Por exemplo, a aplicação configura Uploader com Concurrency definida como 5. Se a aplicação então chamar Upload de duas goroutines diferentes, o resultado será 10 uploads de partes simultâneos (2 goroutines * 5 Concurrency).

Atenção

Espera-se que a aplicação limite as chamadas simultâneas para Upload a fim de evitar o esgotamento dos recursos da aplicação.

Veja a seguir um exemplo para definir o tamanho padrão da parte durante a criação de Uploader:

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

Para obter mais informações Uploader e suas configurações, consulte Uploader na Referência da AWS SDK para Go API.

PutObjectInput Campo corporal (io. ReadSeeker versus io.Reader)

O campo Body da estrutura s3.PutObjectInput é um tipo io.Reader. No entanto, esse campo pode ser preenchido com um tipo que satisfaça tanto a interface io.ReadSeeker quanto io.ReaderAt a fim de melhorar a utilização dos recursos da aplicação no ambiente de host. O exemplo a seguir cria o tipo ReadSeekerAt que satisfaz as duas interfaces:

type ReadSeekerAt interface { io.ReadSeeker io.ReaderAt }

Para tipos io.Reader, os bytes do leitor devem ser armazenados em buffer na memória antes de fazer upload da parte. Quando você aumenta o valor de PartSize ou Concurrency, a memória (RAM) necessária para Uploader aumenta significativamente. A memória necessária é de aproximadamente PartSize * Concurrency. Por exemplo, especificar 100 MB para PartSize e 10 para Concurrency, requer pelo menos 1 GB.

Como um tipo io.Reader não pode determinar seu tamanho antes de ler seus bytes, Uploader não consegue calcular quantas partes serão carregadas. Consequentemente, Uploader pode atingir o limite de upload do Amazon S3 de 10 mil partes para arquivos grandes caso você defina PartSize muito baixo. Se você tentar fazer upload de mais de 10 mil peças, o upload será interrompido e retornará um erro.

Para valores body que implementam o tipo Uploader, o Uploader não armazena o conteúdo do corpo na memória antes de enviá-lo ao Amazon S3. ReadSeekerAt calcula o número esperado de partes antes de fazer upload de cada arquivo no Amazon S3. Se o valor atual de PartSize exigir mais de 10 mil partes para fazer upload do arquivo, Uploader aumenta o valor do tamanho da parte para que menos partes sejam necessárias.

Como gerenciar uploads com falha

Se um upload para o Amazon S3 falhar, por padrão, Uploader usa a operação AbortMultipartUpload do Amazon S3 para remover as partes carregadas. Essa funcionalidade garante que os uploads com falha não consumam o armazenamento do Amazon S3.

Você pode definir LeavePartsOnError como verdadeiro para que Uploader não exclua as partes enviadas com sucesso. Isso é útil para retomar uploads parcialmente concluídos. Para operar com partes carregadas, você deve obter o UploadID do upload que falhou. O exemplo a seguir demonstra como usar o tipo de interface de erro manager.MultiUploadFailure para obter o 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 }

Substituir as opções do uploader por upload

Você pode substituir as opções do Uploader ao chamar Upload fornecendo um ou mais argumentos para o método. Essas substituições são modificações seguras para a simultaneidade e não afetam os uploads em andamento nem as chamadas subsequentes de Upload ao gerenciador. Por exemplo, para substituir a configuração PartSize de uma solicitação de upload específica:

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 })

Exemplos

Fazer upload de uma pasta no Amazon S3

O exemplo a seguir usa o pacote path/filepath para reunir recursivamente uma lista de arquivos e fazer upload deles no bucket do Amazon S3. As chaves dos objetos do Amazon S3 têm como prefixo o caminho relativo do arquivo.

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 }

Gerenciador de downloads

O gerenciador de downloads do Amazon S3 determina se um arquivo pode ser dividido em partes menores e baixado paralelamente. Você pode personalizar o número de downloads paralelos e o tamanho das partes baixadas.

Exemplo: baixar um arquivo

O seguinte exemplo usa o Downloader do Amazon S3 para baixar um arquivo. DownloaderO uso é semelhante ao s3. GetObjectoperação.

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"), })

O parâmetro downloadFile é um tipo io.WriterAt. A interface WriterAt permite que o Downloader grave várias partes do arquivo em paralelo.

Opções de configuração

Ao instanciar uma instância Downloader, você pode especificar opções de configuração para personalizar como os objetos são baixados:

  • PartSize: especifica o tamanho do buffer, em bytes, de cada parte a ser baixada. O tamanho mínimo por parte é de 5 MB.

  • Concurrency: especifica o número exato de partes a serem baixadas em paralelo.

O valor de Concurrency limita o número simultâneo de downloads de partes que podem ocorrer em determinada chamada de Download. Esse não é um limite global de simultaneidade de clientes. Ajuste os valores de configuração PartSize e Concurrency para encontrar a configuração ideal. Por exemplo, sistemas com conexões de alta largura de banda podem receber partes maiores e mais downloads em paralelo.

Por exemplo, a aplicação configura Downloader com Concurrency de 5. Como a aplicação chama Download de duas goroutines diferentes, o resultado será 10 downloads de partes simultâneos (2 goroutines * 5 Concurrency).

Atenção

Espera-se que a aplicação limite as chamadas simultâneas para Download a fim de evitar o esgotamento dos recursos da aplicação.

Para obter mais informações sobre Downloader suas outras opções de configuração, consulte Manager.downloader na Referência da API. AWS SDK para Go

Substituir as opções do downloader por download

Você pode substituir as opções do Downloader ao chamar Download fornecendo um ou mais argumentos funcionais para o método. Essas substituições são modificações seguras para a simultaneidade e não afetam os uploads em andamento nem as chamadas subsequentes de Download ao gerenciador. Por exemplo, para substituir a configuração PartSize de uma solicitação de upload específica:

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 })
Exemplos
Baixar todos os objetos em um bucket

O exemplo a seguir usa paginação para reunir uma lista de objetos de um bucket do Amazon S3. Depois, ele baixa cada objeto em um arquivo local.

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é uma função utilitária para determinar a localização AWS da região de um bucket do Amazon S3. GetBucketRegionpega um cliente Amazon S3 e o usa para determinar a localização do bucket solicitado na AWS partição associada à região configurada do cliente.

Por exemplo, para encontrar a região do bucket 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)

Se não GetBucketRegion for possível resolver a localização de um Bucket, a função retornará um tipo de BucketNotFounderro, conforme mostrado no exemplo.

Entrada de streaming não posicionável

Para operações de API como PutObject e UploadPart, o cliente do Amazon S3 espera que o valor do parâmetro de entrada Body implemente a interface io.Seeker por padrão. A interface io.Seeker é usada pelo cliente para determinar o tamanho do valor a ser carregado e para calcular o hash da carga útil para a assinatura da solicitação. Se o valor do parâmetro de entrada Body não implementar io.Seeker, a aplicação receberá um erro.

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

Você pode alterar esse comportamento modificando o Middleware do método da operação usando opções funcionais. O APIOptions auxiliar With retorna uma opção funcional para zero ou mais mutadores de middleware. Para desativar o cliente computando o hash da carga útil e usar a assinatura de solicitação de carga não assinada, adicione 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, ))
Atenção

O Amazon S3 exige que o tamanho do conteúdo seja fornecido para todos os objetos carregados em um bucket. Como o parâmetro de entrada Body não implementa a interface io.Seeker, o cliente não pode calcular o parâmetro ContentLength para a solicitação. O parâmetro deve ser fornecido pela aplicação. A solicitação falhará se o parâmetro ContentLength não for fornecido.

Use os Gerenciador de uploads do Amazon S3 do SDK para uploads que não são posicionáveis e não possuem um tamanho conhecido.