O recurso de multipart upload do Object Storage Service (OSS) permite dividir um objeto grande em várias partes e enviá-las separadamente. Após enviar todas as partes, chame a operação CompleteMultipartUpload para combiná-las em um objeto completo.
Observações
Os códigos de exemplo neste tópico usam o ID da região
cn-hangzhoupara a região China (Hangzhou) e um endpoint público por padrão. Ao acessar o OSS a partir de outros serviços da Alibaba Cloud na mesma região, use um endpoint interno. Para mais informações sobre regiões e endpoints do OSS, consulte Regiões e endpoints.Os exemplos deste tópico leem credenciais de acesso de variáveis de ambiente. Para saber como configurar credenciais de acesso, consulte Configurar credenciais de acesso.
Para realizar um multipart upload, você precisa da permissão
oss:PutObject. Para mais detalhes, consulte Conceder permissões personalizadas a um usuário RAM.
Processo de multipart upload
O multipart upload consiste nas três etapas a seguir:
-
Inicialize um evento de multipart upload.
Chame o método Client.InitiateMultipartUpload para obter um ID de upload globalmente exclusivo do OSS.
-
Envie as partes.
Chame o método Client.UploadPart para enviar as partes.
NotaPara um determinado ID de upload, o número da parte identifica sua posição no objeto. Se você enviar uma nova parte com um número já existente, o OSS substituirá a parte anterior.
O OSS inclui o hash MD5 da parte recebida no cabeçalho ETag da resposta.
O OSS calcula o hash MD5 dos dados enviados e o compara com o hash calculado pelo kit de desenvolvimento de software (SDK). Se os hashes não coincidirem, o OSS retornará o código de erro
InvalidDigest.
-
Conclua o multipart upload.
Após enviar todas as partes, chame o método Client.CompleteMultipartUpload para combiná-las em um objeto completo.
Código de exemplo
O código a seguir demonstra como dividir um arquivo local grande em várias partes, enviá-las simultaneamente para um bucket e combiná-las em um objeto completo.
package main
import (
"bufio"
"bytes"
"context"
"flag"
"io"
"log"
"os"
"sync"
"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)
// Define global variables.
var (
region string // The region where the bucket is located.
bucketName string // The name of the source bucket.
objectName string // The name of the source object.
)
// The init function initializes command-line parameters.
func init() {
flag.StringVar(®ion, "region", "", "The region in which the bucket is located.")
flag.StringVar(&bucketName, "bucket", "", "The name of the source bucket.")
flag.StringVar(&objectName, "object", "", "The name of the source object.")
}
func main() {
// Parse command-line parameters.
flag.Parse()
// Define the upload ID.
var uploadId string
// Check if the source bucket name is empty.
if len(bucketName) == 0 {
flag.PrintDefaults()
log.Fatalf("invalid parameters, source bucket name required")
}
// Check if the region is empty.
if len(region) == 0 {
flag.PrintDefaults()
log.Fatalf("invalid parameters, region required")
}
// Check if the source object name is empty.
if len(objectName) == 0 {
flag.PrintDefaults()
log.Fatalf("invalid parameters, source object name required")
}
// Load default configurations and set the credential provider and region.
cfg := oss.LoadDefaultConfig().
WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
WithRegion(region)
// Create an OSS client.
client := oss.NewClient(cfg)
// Initialize the multipart upload request.
initRequest := &oss.InitiateMultipartUploadRequest{
Bucket: oss.Ptr(bucketName),
Key: oss.Ptr(objectName),
}
initResult, err := client.InitiateMultipartUpload(context.TODO(), initRequest)
if err != nil {
log.Fatalf("failed to initiate multipart upload %v", err)
}
// Print the result of the multipart upload initialization.
log.Printf("initiate multipart upload result:%#v\n", *initResult.UploadId)
uploadId = *initResult.UploadId
// Initialize the wait group and mutex.
var wg sync.WaitGroup
var parts []oss.UploadPart
count := 3
var mu sync.Mutex
// Read the local file into memory. Replace yourLocalFile with the actual local file name and path.
file, err := os.Open("yourLocalFile")
if err != nil {
log.Fatalf("failed to open local file %v", err)
}
defer file.Close()
bufReader := bufio.NewReader(file)
content, err := io.ReadAll(bufReader)
if err != nil {
log.Fatalf("failed to read local file %v", err)
}
log.Printf("file size: %d\n", len(content))
// Calculate the size of each part.
chunkSize := len(content) / count
if chunkSize == 0 {
chunkSize = 1
}
// Start multiple goroutines to upload parts concurrently.
for i := 0; i < count; i++ {
start := i * chunkSize
end := start + chunkSize
if i == count-1 {
end = len(content)
}
wg.Add(1)
go func(partNumber int, start, end int) {
defer wg.Done()
// Create an upload part request.
partRequest := &oss.UploadPartRequest{
Bucket: oss.Ptr(bucketName), // The name of the destination bucket.
Key: oss.Ptr(objectName), // The name of the destination object.
PartNumber: int32(partNumber), // The part number.
UploadId: oss.Ptr(uploadId), // The upload ID.
Body: bytes.NewReader(content[start:end]), // The content of the part.
}
// Send the upload part request.
partResult, err := client.UploadPart(context.TODO(), partRequest)
if err != nil {
log.Fatalf("failed to upload part %d: %v", partNumber, err)
}
// Record the result of the part upload.
part := oss.UploadPart{
PartNumber: partRequest.PartNumber,
ETag: partResult.ETag,
}
// Use a mutex to protect shared data.
mu.Lock()
parts = append(parts, part)
mu.Unlock()
}(i+1, start, end)
}
// Wait for all goroutines to complete.
wg.Wait()
// Complete the multipart upload request.
request := &oss.CompleteMultipartUploadRequest{
Bucket: oss.Ptr(bucketName),
Key: oss.Ptr(objectName),
UploadId: oss.Ptr(uploadId),
CompleteMultipartUpload: &oss.CompleteMultipartUpload{
Parts: parts,
},
}
result, err := client.CompleteMultipartUpload(context.TODO(), request)
if err != nil {
log.Fatalf("failed to complete multipart upload %v", err)
}
// Print the result of the completed multipart upload.
log.Printf("complete multipart upload result:%#v\n", result)
}
Cenários comuns
Enviar uma string aleatória de comprimento especificado usando multipart upload
Cancele um evento específico de multipart upload
Listar partes enviadas com sucesso em um evento específico de multipart upload
Listar eventos de multipart upload
Multipart upload com callbacks
Multipart upload com barra de progresso
Referências
Para o código de exemplo completo de multipart upload, consulte o exemplo no GitHub.
-
Um multipart upload completo envolve três operações de API:
Para informações sobre a operação de API para inicializar um evento de multipart upload, consulte InitiateMultipartUpload.
Para informações sobre a operação de API para enviar uma parte, consulte UploadPart.
Para informações sobre a operação de API para concluir um multipart upload, consulte CompleteMultipartUpload.
Para informações sobre a operação de API para cancele um evento de multipart upload, consulte AbortMultipartUpload.
Para informações sobre a operação de API para listar partes enviadas, consulte NewListPartsPaginator.
Para informações sobre a operação de API para listar todos os eventos de multipart upload em andamento (eventos iniciados, mas ainda não concluídos ou cancelados), consulte NewListMultipartUploadsPaginator.