Object Storage Service (OSS) provides the multipart upload feature. Multipart upload allows you to split a large object into multiple parts to upload. After these parts are uploaded, you can call CompleteMultipartUpload to combine the parts into a complete object to implement resumable upload.
Process
To upload an object by using multipart upload, perform the following steps:
- Initiate a multipart upload task.
You can call the oss.initMultipartUpload method to create a unique upload ID in OSS.
- Upload parts.
You can call the oss.uploadPart method to upload parts.
Note- If parts are uploaded by a multipart upload task that has a specific upload ID, part numbers are used to identify the relative positions of the parts in an object. If you upload a part that has the same part number as an existing part, the existing part is overwritten by the uploaded part.
- OSS includes the MD5 hash of each uploaded part in the ETag header in the response.
- OSS calculates the MD5 hash of uploaded data and compares the MD5 hash with the MD5 hash that is calculated by OSS SDK for Java. If the two hashes are different, OSS returns the InvalidDigest error code.
- Complete the multipart upload task.
After all parts are uploaded, you can call the oss.CompleteMultipartUpload method to combine the parts into a complete object.
Complete sample code
The following code provides an example on how to perform multipart upload:
// Specify the bucket name. Example: examplebucket.
String bucketName = "examplebucket";
// Specify the full path of the object. Example: exampledir/exampleobject.txt. The full path of the object cannot contain the bucket name.
String objectName = "exampledir/exampleobject.txt";
// Specify the full path of the local file that you want to upload to OSS by using multipart upload. Example: /storage/emulated/0/oss/examplefile.txt.
String localFilepath = "/storage/emulated/0/oss/examplefile.txt";
// Initiate a multipart upload task.
InitiateMultipartUploadRequest init = new InitiateMultipartUploadRequest(bucketName, objectName);
InitiateMultipartUploadResult initResult = oss.initMultipartUpload(init);
// Obtain the upload ID, which uniquely identifies the multipart upload task. You can use the upload ID to cancel or query the multipart upload task.
String uploadId = initResult.getUploadId();
// Specify the size of each part. Unit: bytes. Valid values: 100 KB to 5 GB.
int partCount = 100 * 1024;
// Start the multipart upload task.
List<PartETag> partETags = new ArrayList<>();
for (int i = 1; i < 5; i++) {
byte[] data = new byte[partCount];
RandomAccessFile raf = new RandomAccessFile(localFilepath, "r");
long skip = (i-1) * partCount;
raf.seek(skip);
raf.readFully(data, 0, partCount);
UploadPartRequest uploadPart = new UploadPartRequest();
uploadPart.setBucketName(bucketName);
uploadPart.setObjectKey(objectName);
uploadPart.setUploadId(uploadId);
// Specify the part number of each part. The number starts from 1. Each part that you want to upload has a part number. Valid values: 1 to 10000.
uploadPart.setPartNumber(i);
uploadPart.setPartContent(data);
try {
UploadPartResult result = oss.uploadPart(uploadPart);
PartETag partETag = new PartETag(uploadPart.getPartNumber(), result.getETag());
partETags.add(partETag);
} catch (ServiceException serviceException) {
OSSLog.logError(serviceException.getErrorCode());
}
}
Collections.sort(partETags, new Comparator<PartETag>() {
@Override
public int compare(PartETag lhs, PartETag rhs) {
if (lhs.getPartNumber() < rhs.getPartNumber()) {
return -1;
} else if (lhs.getPartNumber() > rhs.getPartNumber()) {
return 1;
} else {
return 0;
}
}
});
// Complete the multipart upload task.
CompleteMultipartUploadRequest complete = new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);
// Implement upload callback. You can set the CALLBACK_SERVER parameter when you complete the multipart upload task. A callback request is sent to the specified server address after you complete the multipart upload task. You can view the server callback result in completeResult.getServerCallbackReturnBody() of the response.
complete.setCallbackParam(new HashMap<String, String>() {
{
put("callbackUrl", CALLBACK_SERVER); // Set the CALLBACK_SERVER parameter to your server address.
put("callbackBody", "test");
}
});
CompleteMultipartUploadResult completeResult = oss.completeMultipartUpload(complete);
OSSLog.logError("-------------- serverCallback: " + completeResult.getServerCallbackReturnBody());
The preceding code uses uploadPart to upload each part.
- You must specify the upload ID and part numbers for each multipart upload request. Valid values of PartNumber range from 1 to 10000. If a part number is not within this range, the InvalidArgument error code is returned.
- If you use uploadPart, parts must be larger than 100 KB except for the last part When you use uploadPart, the size of each part is verified only after all parts are uploaded.
- Each time you upload a part, make sure that the stream is directed to the start position of the part that you want to upload.
- Each time a part is uploaded, OSS returns a response that contains the ETag value of the part. If the ETag value is the same as the MD5 hash, combine the ETag value with the part number into a PartETag and save the PartETag for subsequent uploads of parts.
Upload a local file by using multipart upload
You can upload local files to OSS by using multipart upload in synchronous mode or in asynchronous mode.
- Upload a local file by using multipart upload in synchronous mode
The following code provides an example on how to upload a local file named examplefile.txt to the exampleobject.txt object in the exampledir directory of the examplebucket bucket by using multipart upload in synchronous mode:
// Specify the bucket name. Example: examplebucket. String bucketName = "examplebucket"; // Specify the full path of the object. Example: exampledir/exampleobject.txt. The full path of the object cannot contain the bucket name. String objectName = "exampledir/exampleobject.txt"; // Specify the full path of the local file that you want to upload to OSS by using multipart upload. Example: /storage/emulated/0/oss/examplefile.txt. String localFilepath = "/storage/emulated/0/oss/examplefile.txt"; ObjectMetadata meta = new ObjectMetadata(); // Configure object metadata. meta.setHeader("x-oss-object-acl", "public-read-write"); MultipartUploadRequest rq = new MultipartUploadRequest(bucketName, objectName, localFilepath, meta); // Set PartSize. The default value of PartSize is 256 KB. The minimum value is 100 KB. rq.setPartSize(1024 * 1024); rq.setProgressCallback(new OSSProgressCallback<MultipartUploadRequest>() { @Override public void onProgress(MultipartUploadRequest request, long currentSize, long totalSize) { OSSLog.logDebug("[testMultipartUpload] - " + currentSize + " " + totalSize, false); } }); CompleteMultipartUploadResult result = oss.multipartUpload(rq);
For partition storage of Android 10 and later versions, you can use the Uniform Resource Identifier (URI) of a file to upload the file to OSS.
// Specify the bucket name. Example: examplebucket. String bucketName = "examplebucket"; // Specify the full path of the object. Example: exampledir/exampleobject.txt. The full path of the object cannot contain the bucket name. String objectName = "exampledir/exampleobject.txt"; ObjectMetadata meta = new ObjectMetadata(); // Configure object metadata. meta.setHeader("x-oss-object-acl", "public-read-write"); MultipartUploadRequest rq = new MultipartUploadRequest(bucketName, objectName, fileUri, meta); // Set PartSize. The default value of PartSize is 256 KB. The minimum value is 100 KB. rq.setPartSize(1024 * 1024); rq.setProgressCallback(new OSSProgressCallback<MultipartUploadRequest>() { @Override public void onProgress(MultipartUploadRequest request, long currentSize, long totalSize) { OSSLog.logDebug("[testMultipartUpload] - " + currentSize + " " + totalSize, false); } }); CompleteMultipartUploadResult result = oss.multipartUpload(rq);
- Upload a local file by using multipart upload in asynchronous mode
The following code provides an example on how to upload a local file named examplefile.txt to the exampleobject.txt object in the exampledir directory of the examplebucket bucket by using multipart upload in asynchronous mode:
// Specify the bucket name. Example: examplebucket. String bucketName = "examplebucket"; // Specify the full path of the object. Example: exampledir/exampleobject.txt. The full path of the object cannot contain the bucket name. String objectName = "exampledir/exampleobject.txt"; // Specify the full path of the local file that you want to upload to OSS by using multipart upload. Example: /storage/emulated/0/oss/examplefile.txt. String localFilepath = "/storage/emulated/0/oss/examplefile.txt"; MultipartUploadRequest request = new MultipartUploadRequest(bucketName, objectName, localFilepath); request.setProgressCallback(new OSSProgressCallback<MultipartUploadRequest>() { @Override public void onProgress(MultipartUploadRequest request, long currentSize, long totalSize) { OSSLog.logDebug("[testMultipartUpload] - " + currentSize + " " + totalSize, false); } }); OSSAsyncTask task = oss.asyncMultipartUpload(request, new OSSCompletedCallback<MultipartUploadRequest, CompleteMultipartUploadResult>() { @Override public void onSuccess(MultipartUploadRequest request, CompleteMultipartUploadResult result) { OSSLog.logInfo(result.getServerCallbackReturnBody()); } @Override public void onFailure(MultipartUploadRequest request, ClientException clientException, ServiceException serviceException) { OSSLog.logError(serviceException.getRawMessage()); } }); //Thread.sleep(100); // Cancel the multipart upload task. //task.cancel(); task.waitUntilFinished();
For partition storage of Android 10 and later versions, you can use the URI of a file to upload the file to OSS.
// Specify the bucket name. Example: examplebucket. String bucketName = "examplebucket"; // Specify the full path of the object. Example: exampledir/exampleobject.txt. The full path of the object cannot contain the bucket name. String objectName = "exampledir/exampleobject.txt"; MultipartUploadRequest request = new MultipartUploadRequest(bucketName, objectName, fileUri); request.setProgressCallback(new OSSProgressCallback<MultipartUploadRequest>() { @Override public void onProgress(MultipartUploadRequest request, long currentSize, long totalSize) { OSSLog.logDebug("[testMultipartUpload] - " + currentSize + " " + totalSize, false); } }); OSSAsyncTask task = oss.asyncMultipartUpload(request, new OSSCompletedCallback<MultipartUploadRequest, CompleteMultipartUploadResult>() { @Override public void onSuccess(MultipartUploadRequest request, CompleteMultipartUploadResult result) { OSSLog.logInfo(result.getServerCallbackReturnBody()); } @Override public void onFailure(MultipartUploadRequest request, ClientException clientException, ServiceException serviceException) { OSSLog.logError(serviceException.getRawMessage()); } }); //Thread.sleep(100); // Cancel the multipart upload task. //task.cancel(); task.waitUntilFinished();
List uploaded parts
You can call the oss.listParts method to obtain all parts that are uploaded in a multipart upload task.
The following code provides an example on how to list uploaded parts:
// Specify the bucket name. Example: examplebucket.
String bucketName = "examplebucket";
// Specify the full path of the object. Example: exampledir/exampleobject.txt. The full path of the object cannot contain the bucket name.
String objectName = "exampledir/exampleobject.txt";
// Specify the upload ID.
String uploadId = "0004B999EF518A1FE585B0C9****";
// List uploaded parts.
ListPartsRequest listParts = new ListPartsRequest(bucketName, objectName, uploadId);
ListPartsResult result = oss.listParts(listParts);
List<PartETag> partETagList = new ArrayList<PartETag>();
for (PartSummary part : result.getParts()) {
partETagList.add(new PartETag(part.getPartNumber(), part.getETag()));
}
Cancel a multipart upload task
You can call the oss.abortMultipartUpload method to cancel a multipart upload task. If you cancel a multipart upload task, you cannot use the upload ID to upload parts. The uploaded parts are deleted.
The following code provides an example on how to cancel a multipart upload task:
// Specify the bucket name. Example: examplebucket.
String bucketName = "examplebucket";
// Specify the full path of the object. Example: exampledir/exampleobject.txt. The full path of the object cannot contain the bucket name.
String objectName = "exampledir/exampleobject.txt";
// Specify the upload ID.
String uploadId = "0004B999EF518A1FE585B0C9****";
// Cancel the multipart upload task.
AbortMultipartUploadRequest abort = new AbortMultipartUploadRequest(bucketName, objectName, uploadId);
AbortMultipartUploadResult abortResult = oss.abortMultipartUpload(abort);
References
- For the complete sample code that is used to perform multipart upload, visit GitHub.
- The following API operations are required to perform multipart upload:
- The API operation that you can call to initiate a multipart upload task. For more information, see InitiateMultipartUpload.
- The API operation that you can call to upload data by part. For more information, see UploadPart.
- The API operation that you can call to complete a multipart upload task. For more information, see CompleteMultipartUpload.
- For more information about the API operation that you can call to cancel a multipart upload task, see AbortMultipartUpload.
- For more information about the API operation that you can call to list uploaded parts, see ListParts.
- For more information about the API operation that you can call to list ongoing multipart upload tasks, see ListMultipartUploads. Ongoing multipart upload tasks include tasks that have been initiated but are not completed and tasks that have been canceled.