By using the multipart upload feature provided by OSS, you can split a large object into multiple parts and upload them separately. After all parts are uploaded, call the CompleteMultipartUpload operation to combine these parts into a single object to implement resumable upload.

Multipart upload process

To implement multipart upload, perform the following operations:

  1. Initiate a multipart upload task.

    You can call the Bucket.InitiateMultipartUpload method to obtain a unique upload ID in OSS.

  2. Upload the parts.

    You can call the Bucket.UploadPart method to upload the parts.

    Note
    • Part numbers identify the relative positions of parts in an object that share the same upload ID. If you have uploaded a part and used its part number again to upload another part, the latter part overwrites the former part.
    • OSS includes the MD5 hash of part data in the ETag header and returns the MD5 hash to the user.
    • OSS calculates the MD5 hash of uploaded data and compares it with the MD5 hash calculated by the SDK. If the two hashes are different, the InvalidDigest error code is returned.
  3. Complete the multipart upload task.

    After all parts are uploaded, call the Bucket.CompleteMultipartUpload method to combine the parts into a complete object.

Complete sample code of multipart upload

The following code provides a complete example that describes the process of multipart upload:

package main

import (
    "fmt"
    "os"

    "github.com/aliyun/aliyun-oss-go-sdk/oss"
)

func main() {
    // Create an OSSClient instance.
    client, err := oss.New("<yourEndpoint>", "<yourAccessKeyId>", "<yourAccessKeySecret>")
    if err ! = nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }

    bucketName := "<yourBucketName>"
    objectName := "<yourObjectName>"
    locaFilename := "<yourLocalFilename>"

    // Obtain information about the bucket.
    bucket, err := client.Bucket(bucketName)
    if err ! = nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
    chunks, err := oss.SplitFileByPartNum(locaFilename, 3)
    fd, err := os.Open(locaFilename)
    defer fd.Close()

    // Set the storage class to Archive.
    storageType := oss.ObjectStorageClass(oss.StorageStandard)

    // Step 1: Initiate a multipart upload task. Set the storage class to Standard.
    imur, err := bucket.InitiateMultipartUpload(objectName, storageType)
    // Step 2: Upload the parts.
    var parts []oss.UploadPart
    for _, chunk := range chunks {
        fd.Seek(chunk.Offset, os.SEEK_SET)
        // Call the UploadPart method to upload each part.
        part, err := bucket.UploadPart(imur, fd, chunk.Size, chunk.Number)
        if err ! = nil {
            fmt.Println("Error:", err)
            os.Exit(-1)
        }
        parts = append(parts, part)
    }

    // Set the ACL of the object to public read. By default, the object inherits the ACL of the bucket.
    objectAcl := oss.ObjectACL(oss.ACLPublicRead)

    // Step 3: Complete the multipart upload task. Set the ACL to public read.
    cmur, err := bucket.CompleteMultipartUpload(imur, parts, objectAcl)
    if err ! = nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
    fmt.Println("cmur:", cmur)
}

Cancel a multipart upload task

You can call the bucket.AbortMultipartUpload method to cancel a multipart upload task. If you cancel a multipart upload task, you cannot use the upload ID to upload any part. The uploaded parts are deleted.

The following code provides an example on how to cancel a multipart upload task:

package main
import (
    "fmt"
    "os"
    "github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func main() {
    // Create an OSSClient instance.
    client, err := oss.New("<yourEndpoint>", "<yourAccessKeyId>", "<yourAccessKeySecret>")
    if err ! = nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
    // Obtain information about the bucket.
    bucket, err := client.Bucket("<yourBucketName>")
    if err ! = nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
    // Initiate a multipart upload task.
    imur, err := bucket.InitiateMultipartUpload("<yourObjectName>")
    if err ! = nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
    // Cancel the multipart upload task.
    err = bucket.AbortMultipartUpload(imur)
    if err ! = nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
}

List uploaded parts

The following code provides an example on how to list the parts uploaded in a specified multipart upload task:

package main
import (
    "fmt"
    "os"
    "github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func main() {
    // Create an OSSClient instance.
    client, err := oss.New("<yourEndpoint>", "<yourAccessKeyId>", "<yourAccessKeySecret>")
    if err ! = nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
    bucketName := "<yourBucketName>"
    objectName := "<yourObjectName>"
    locaFilename := "<yourLocalFilename>"
    uploadID := "<yourUploadID>"
    // Obtain information about the bucket.
    bucket, err := client.Bucket(bucketName)
    if err ! = nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
    // Split the local file into three parts.
    chunks, err := oss.SplitFileByPartNum(locaFilename, 3)
    fd, err := os.Open(locaFilename)
    defer fd.Close()
    // Initiate a multipart upload task.
    imur, err := bucket.InitiateMultipartUpload(objectName)
    uploadID = imur.UploadID
    fmt.Println("InitiateMultipartUpload UploadID: ", uploadID)
    if err ! = nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
    // Upload the parts.
    var parts []oss.UploadPart
    for _, chunk := range chunks {
        fd.Seek(chunk.Offset, os.SEEK_SET)
        // Call the UploadPart method to upload each part.
        part, err := bucket.UploadPart(imur, fd, chunk.Size, chunk.Number)
        if err ! = nil {
            fmt.Println("Error:", err)
            os.Exit(-1)
        }
        fmt.Println("UploadPartNumber: ", part.PartNumber, ", ETag: ", part.ETag)
        parts = append(parts, part)
    }
    // List the uploaded parts based on the result obtained by using the InitiateMultipartUploadResult operation.
    lsRes, err := bucket.ListUploadedParts(imur)
    if err ! = nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
    // Display the uploaded parts. 
    fmt.Println("\nParts:", lsRes.UploadedParts)
    for _, upload := range lsRes.UploadedParts {
        fmt.Println("List PartNumber:  ", upload.PartNumber, ", ETag: " ,upload.ETag, ", LastModified: ", upload.LastModified)
    }
    // Specify objectName and UploadID to obtain the result by using the InitiateMultipartUploadResult operation. List all uploaded parts based on the result.
    var imur_with_uploadid oss.InitiateMultipartUploadResult
    imur_with_uploadid.Key = objectName
    imur_with_uploadid.UploadID = uploadID
    // List all the uploaded parts.
    lsRes, err = bucket.ListUploadedParts(imur_with_uploadid)
    if err ! = nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
    // Display the uploaded parts.
    fmt.Println("\nListUploadedParts by UploadID: ", uploadID)
    for _, upload := range lsRes.UploadedParts {
        fmt.Println("List PartNumber:  ", upload.PartNumber, ", ETag: " ,upload.ETag, ", LastModified: ", upload.LastModified)
    }
    // Complete the multipart upload task.
    cmur, err := bucket.CompleteMultipartUpload(imur, parts)
    if err ! = nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
    fmt.Println("cmur:", cmur)
}

List multipart upload tasks

You can call the Bucket.ListMultipartUploads method to list all ongoing multipart upload tasks that have been initiated but not completed or that have been canceled. The following table describes the parameters of this operation.

Parameter Description
Delimiter Specifies the character used to group objects by name. If you specify the Delimiter parameter in the request, the response contains the CommonPrefixes element. Objects whose names contain the same string from the prefix and the next occurrence of the delimiter are grouped as a single result element in CommonPrefixes.
MaxUploads Specifies the maximum number of multipart upload tasks to return each time. The default value is 1000. The maximum value is 1000.
KeyMarker Specifies the name of the object after which the list of multipart upload tasks begins. All multipart upload tasks with objects whose names are alphabetically greater than the KeyMarker parameter value are included in the list. You can use this parameter with the UploadIDMarker parameter to specify the start position to list the returned results.
Prefix Specifies the prefix that returned object names must contain. Note that if you use a prefix for a query, the returned object name contains the prefix.
UploadIDMarker Specifies the start position from which to list returned results. This parameter is used together with the KeyMarker parameter.
  • This parameter is ignored if the KeyMarker parameter is not set.
  • If the KeyMarker parameter is set, the response includes the following tasks:
    • Multipart upload tasks whose object names are alphabetically greater than the KeyMarker parameter value.
    • Multipart upload tasks whose object names are equal to the KeyMarker parameter value but whose upload IDs are greater than the UploadIDMarker parameter value.
  • List multipart upload tasks by using default parameter values
    package main
    import (
        "fmt"
        "os"
        "github.com/aliyun/aliyun-oss-go-sdk/oss"
    )
    func main() {
        // Create an OSSClient instance.
        client, err := oss.New("<yourEndpoint>", "<yourAccessKeyId>", "<yourAccessKeySecret>")
        if err ! = nil {
            fmt.Println("Error:", err)
            os.Exit(-1)
        }
        // Obtain information about the bucket.
        bucketName := "<yourBucketName>"
        bucket, err := client.Bucket(bucketName)
        if err ! = nil {
            fmt.Println("Error:", err)
            os.Exit(-1)
        }
        // List all multipart upload tasks.
        keyMarker := ""
        uploadIdMarker := ""
        for {
            // By default, up to 1,000 records are listed each time. 
            lsRes, err := bucket.ListMultipartUploads(oss.KeyMarker(keyMarker), oss.UploadIDMarker(uploadIdMarker))
            if err ! = nil {
                fmt.Println("Error:", err)
                os.Exit(-1)
            }
            // Display all the multipart upload tasks. 
            for _, upload := range lsRes.Uploads {
                fmt.Println("Upload: ", upload.Key, ", UploadID: ",upload.UploadID)
            }
            if lsRes.IsTruncated {
                keyMarker = lsRes.NextKeyMarker
                uploadIdMarker = lsRes.NextUploadIDMarker
            } else {
                break
            }
        }
    }
  • List multipart upload tasks by specifying a prefix
        lsRes, err := bucket.ListMultipartUploads(oss.Prefix("<yourObjectNamePrefix>"))
        if err ! = nil {
            fmt.Println("Error:", err)
            os.Exit(-1)
        }
        fmt.Println("Uploads:", lsRes.Uploads)
  • List up to 100 multipart upload tasks
        lsRes, err := bucket.ListMultipartUploads(oss.MaxUploads(100))
        if err ! = nil {
            fmt.Println("Error:", err)
            os.Exit(-1)
        }
        fmt.Println("Uploads:", lsRes.Uploads)
  • List multipart upload tasks by specifying a prefix and the maximum number of records to return
        lsRes, err := bucket.ListMultipartUploads(oss.Prefix("<yourObjectNamePrefix>"), oss.MaxUploads(100))
        if err ! = nil {
            fmt.Println("Error:", err)
            os.Exit(-1)
        }
        fmt.Println("Uploads:", lsRes.Uploads)