Object Storage Service (OSS) provides a multipart upload feature. This feature splits a large object into multiple parts. After you upload these parts, you can call the CompleteMultipartUpload operation to combine them into a complete object.
Usage notes
-
For more information about the regions and endpoints that OSS supports, see Regions and endpoints.
-
To perform a multipart upload, you must have the
oss:PutObjectpermission. For more information, see Grant a custom access policy to a RAM user.
Multipart upload process
A multipart upload consists of the following three steps:
-
Initiate a multipart upload event.
Call the client.initiateMultipartUpload method. OSS returns a globally unique upload ID.
-
Upload parts.
Call the client.uploadPart method to upload the part data.
Note-
For the same upload ID, the part number (partNumber) identifies the position of the part in the complete object. If you upload a new part with the same part number, the existing data of that part in OSS is overwritten.
-
OSS returns the MD5 hash of the received part in the ETag header.
-
OSS calculates the MD5 hash of the uploaded data and compares it with the MD5 hash calculated by the SDK. If the two hashes do not match, OSS returns the InvalidDigest error code.
-
-
Complete the multipart upload.
After all parts are uploaded, call the client.completeMultipartUpload method to combine the parts into a complete object.
Sample code
The following code shows how to split a large local file into multiple parts, upload the parts to a bucket concurrently, and then combine the parts into a complete object.
import Client, { FilePath, RequestError, THarmonyEmptyBodyApiRes } from '@aliyun/oss';
import { fileIo as fs } from '@kit.CoreFileKit';
// Create an OSS client instance.
const client = new Client({
// Replace with the AccessKey ID from your STS temporary access credential.
accessKeyId: 'yourAccessKeyId',
// Replace with the AccessKey secret from your STS temporary access credential.
accessKeySecret: 'yourAccessKeySecret',
// Replace with the security token from your STS temporary access credential.
securityToken: 'yourSecurityToken',
// Specify the region where the bucket is located. For example, if the bucket is in the China (Hangzhou) region, set the region to oss-cn-hangzhou.
region: 'oss-cn-hangzhou',
});
// Specify the name of the bucket. Replace with your actual bucket name.
const bucket = 'yourBucketName';
// Specify the name of the object (file) to upload. Replace with your actual object name.
const key = 'yourObjectName';
/**
* Upload a file to OSS using multipart upload.
* Use multipart upload to split a large file into multiple parts and upload them to a specified bucket and key.
*/
const multipartUpload = async () => {
try {
// Initiate the multipart upload task and get the uploadId.
const initRes = await client.initiateMultipartUpload({
bucket, // The bucket name.
key, // The object (file) name.
});
// Get the uploadId from the initialization response. This ID is used for subsequent part uploads and to complete the upload.
const uploadId = initRes.data.uploadId;
// Specify the local file path.
const filePath = new FilePath('yourFilePath');// Replace with the actual local file path.
// Get the file metadata, such as the file size.
const fileStat = await fs.stat(filePath.filePath);
// Define the size of each part (10 MB).
const chunkSize = 1024 * 1024 * 10;
// Calculate the total number of parts.
let totalParts = Math.ceil(fileStat.size / chunkSize);
// The current part number.
let partNumber = 1;
// Store the Promise objects for all part uploads.
const waitList: Promise<THarmonyEmptyBodyApiRes>[] = [];
// Loop through each part.
while (partNumber <= totalParts) {
// Calculate the start position of the current part.
const offset = (partNumber - 1) * chunkSize;
// Call the uploadPart method to upload the current part.
const uploadPromise = client.uploadPart({
bucket, // The bucket name.
key, // The object (file) name.
uploadId, // The uploadId returned from the initialization.
partNumber, // The current part number.
data: filePath, // The file path.
length: Math.min(chunkSize, fileStat.size - offset), // The size of the current part.
offset, // The start offset of the current part.
});
// Add the part upload Promise to the wait list.
waitList.push(uploadPromise);
// Increment the part number.
partNumber++;
}
// Wait for all part uploads to complete.
const uploadResList = await Promise.all(waitList);
// After all parts are uploaded, call completeMultipartUpload to complete the upload task.
const completeRes = await client.completeMultipartUpload({
bucket, // The bucket name.
key, // The object (file) name.
uploadId, // The uploadId returned from the initialization.
completeAll: true, // Automatically completes all parts.
});
// Print the result of the completed multipart upload.
console.log(JSON.stringify(completeRes));
} catch (err) {
// Catch exceptions that occur during the request.
if (err instanceof RequestError) {
// If a known type of error occurs, print information such as the error code, error message, request ID, and status code.
console.log('code: ', err.code); // Error code.
console.log('message: ', err.message); // Error message.
console.log('requestId: ', err.requestId); // Request ID.
console.log('status: ', err.status); // HTTP status code.
console.log('ec: ', err.ec); // Error code.
} else {
// Print other unknown types of errors.
console.log('unknown error: ', err);
}
}
};
// Call the multipartUpload function to perform the multipart upload operation.
multipartUpload();