O recurso de upload multipartido no Object Storage Service (OSS) permite dividir um objeto grande em várias partes. Envie essas partes separadamente. Após enviar todas as partes, chame a operação CompleteMultipartUpload para combiná-las em um objeto completo.
Observações
O código de exemplo neste tópico usa o ID de região
cn-hangzhoupara a região China (Hangzhou) e usa um endpoint público por padrão. Se você acessar o OSS a partir de outros serviços da Alibaba Cloud na mesma região, use um endpoint interno. Para obter mais informações sobre regiões e endpoints do OSS, consulte Regions and endpoints.Os exemplos neste tópico leem as credenciais de acesso a partir de variáveis de ambiente. Para obter mais informações sobre como configure credenciais de acesso, consulte Configure access credentials.
Para executar um upload multipartido, você deve ter a permissão
oss:PutObject. Para obter mais informações, consulte Grant custom permissions to a RAM user.
Processo de upload multipartido
Um upload multipartido consiste nas três etapas a seguir:
-
Inicialize um evento de upload multipartido.
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 a posição da parte dentro do objeto. Se você enviar uma nova parte com um número de parte já existente, o OSS substituirá a parte existente.
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 upload multipartido.
Após enviar todas as partes, chame o método Client.CompleteMultipartUpload para combinar todas as partes em um objeto completo.
Código de exemplo
O código a seguir mostra como dividir um arquivo local grande em várias partes, enviar essas partes para um bucket simultaneamente e, em seguida, 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
Envie uma string aleatória de comprimento especificado usando upload multipartido
Cancele um evento de upload multipartido específico
Listar partes enviadas com sucesso em um evento de upload multipartido específico
Listar eventos de upload multipartido
Crie upload multipartido com callbacks
Crie upload multipartido com barra de progresso
Referências
Para obter o código de exemplo completo de upload multipartido, consulte o exemplo no GitHub.
-
Um upload multipartido completo envolve três operações de API:
Para obter informações sobre a operação de API para inicializar um evento de upload multipartido, consulte InitiateMultipartUpload.
Para obter informações sobre a operação de API para enviar uma parte, consulte UploadPart.
Para obter informações sobre a operação de API para concluir um upload multipartido, consulte CompleteMultipartUpload.
Para obter informações sobre a operação de API para cancelar um evento de upload multipartido, consulte AbortMultipartUpload.
Para obter informações sobre a operação de API para listar partes enviadas, consulte NewListPartsPaginator.
Para obter informações sobre a operação de API para listar todos os eventos de upload multipartido em andamento, ou seja, eventos iniciados, mas ainda não concluídos ou cancelados, consulte NewListMultipartUploadsPaginator.