Object Storage Service (OSS) menyediakan fitur unggah multi-bagian yang memungkinkan Anda membagi objek besar menjadi beberapa bagian dan mengunggahnya secara independen. Setelah semua bagian diunggah, Anda dapat memanggil operasi CompleteMultipartUpload untuk menggabungkan bagian-bagian tersebut menjadi satu objek utuh. Proses ini mendukung unggah yang dapat dilanjutkan.
Catatan penggunaan
Sebelum menjalankan kode contoh dalam topik ini, Anda harus membuat instans OSSClient dengan menggunakan metode seperti nama domain kustom atau Security Token Service (STS). Untuk informasi selengkapnya, lihat Inisialisasi (Android SDK).
Proses unggah multi-bagian
Unggah multi-bagian terdiri dari tiga langkah berikut:
Menginisiasi event unggah multi-bagian.
Panggil metode oss.initMultipartUpload. OSS kemudian akan mengembalikan uploadId yang bersifat unik secara global.
Mengunggah bagian-bagian.
Panggil metode oss.uploadPart untuk mengunggah setiap bagian.
CatatanUntuk uploadId tertentu, nomor bagian menentukan posisi suatu bagian dalam objek lengkap. Jika Anda mengunggah bagian baru dengan nomor bagian yang sama dengan bagian yang sudah ada, bagian tersebut akan ditimpa.
OSS menyertakan hash MD5 dari data bagian yang diterima dalam header ETag pada respons.
OSS menghitung hash MD5 dari data yang diunggah dan membandingkannya dengan hash MD5 yang dihitung oleh SDK. Jika kedua hash tidak cocok, OSS mengembalikan kode kesalahan InvalidDigest.
Menyelesaikan unggah multi-bagian.
Setelah semua bagian diunggah, panggil metode oss.CompleteMultipartUpload untuk menggabungkan semua bagian menjadi satu objek utuh.
Contoh lengkap unggah multi-bagian
Contoh berikut menunjukkan proses unggah multi-bagian secara lengkap:
// Tentukan nama bucket, misalnya examplebucket.
String bucketName = "examplebucket";
// Tentukan path lengkap objek, misalnya exampledir/exampleobject.txt. Path lengkap objek tidak boleh mengandung nama bucket.
String objectName = "exampledir/exampleobject.txt";
// Tentukan path lengkap file lokal, misalnya /storage/emulated/0/oss/examplefile.txt.
String localFilepath = "/storage/emulated/0/oss/examplefile.txt";
// Inisialisasi unggah multi-bagian.
InitiateMultipartUploadRequest init = new InitiateMultipartUploadRequest(bucketName, objectName);
InitiateMultipartUploadResult initResult = oss.initMultipartUpload(init);
// uploadId dikembalikan.
String uploadId = initResult.getUploadId();
// Gunakan uploadId untuk membatalkan event unggah multi-bagian atau mencantumkan bagian-bagian yang telah diunggah.
// Untuk membatalkan event unggah multi-bagian berdasarkan uploadId, peroleh uploadId setelah memanggil InitiateMultipartUpload untuk menginisialisasi unggah multi-bagian.
// Untuk mencantumkan bagian-bagian yang telah diunggah berdasarkan uploadId, peroleh uploadId setelah memanggil InitiateMultipartUpload untuk menginisialisasi unggah multi-bagian dan sebelum memanggil CompleteMultipartUpload untuk menyelesaikan unggah multi-bagian.
// Log.d("uploadId", uploadId);
// Tetapkan ukuran satu bagian dalam byte. Ukuran minimum suatu bagian adalah 100 KB, dan ukuran maksimum adalah 5 GB. Ukuran bagian terakhir dapat kurang dari 100 KB.
int partCount = 100 * 1024;
// Unggah bagian-bagian.
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);
// Tetapkan nomor bagian, yang dimulai dari 1. Setiap bagian yang diunggah memiliki nomor bagian dalam rentang 1 hingga 10.000.
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;
}
}
});
// Selesaikan unggah multi-bagian.
CompleteMultipartUploadRequest complete = new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);
// Callback unggah. Saat Anda menyelesaikan permintaan unggah multi-bagian, Anda dapat mengatur parameter CALLBACK_SERVER. Setelah permintaan selesai, permintaan callback dikirim ke alamat server yang ditentukan. Anda dapat melihat hasil callback server dari completeResult.getServerCallbackReturnBody() dalam hasil yang dikembalikan.
complete.setCallbackParam(new HashMap<String, String>() {
{
put("callbackUrl", CALLBACK_SERVER); // Ubah nilai ini menjadi alamat server Anda.
put("callbackBody", "test");
}
});
CompleteMultipartUploadResult completeResult = oss.completeMultipartUpload(complete);
OSSLog.logError("-------------- serverCallback: " + completeResult.getServerCallbackReturnBody());Kode di atas memanggil uploadPart untuk mengunggah setiap bagian.
Setiap permintaan unggah bagian harus menentukan uploadId dan partNumber. Nilai partNumber harus berada dalam rentang 1 hingga 10.000. Jika partNumber berada di luar rentang ini, OSS mengembalikan kode kesalahan InvalidArgument.
Saat memanggil uploadPart, semua bagian kecuali bagian terakhir harus berukuran lebih dari 100 KB. OSS hanya memeriksa ukuran bagian saat Anda menyelesaikan unggah multi-bagian.
Sebelum mengunggah setiap bagian, Anda harus memposisikan aliran ke awal data untuk bagian tersebut.
Setelah setiap bagian diunggah, respons OSS berisi nilai ETag untuk bagian tersebut. Nilai ETag merupakan hash MD5 dari data bagian. Anda harus menggabungkan nilai ETag dan nomor bagian menjadi PartETag serta menyimpannya untuk menyelesaikan unggah multi-bagian.
Unggah multi-bagian file lokal
Anda dapat mengunggah file lokal ke OSS menggunakan unggah multi-bagian sinkron atau asinkron.
Bagian sebelumnya memberikan contoh lengkap yang menunjukkan proses unggah multi-bagian langkah demi langkah. Kode dalam bagian ini telah mengenkapsulasi proses tersebut untuk mengunggah file lokal. Anda hanya perlu menggunakan MultipartUploadRequest untuk melakukan unggah multi-bagian.
Unggah file lokal menggunakan operasi unggah multi-bagian sinkron
Kode berikut menunjukkan cara mengunggah file examplefile.txt secara sinkron ke objek exampleobject.txt dalam folder exampledir di bucket examplebucket.
// Tentukan nama bucket, misalnya examplebucket. String bucketName = "examplebucket"; // Tentukan path lengkap objek, misalnya exampledir/exampleobject.txt. Path lengkap objek tidak boleh mengandung nama bucket. String objectName = "exampledir/exampleobject.txt"; // Tentukan path lengkap file lokal, misalnya /storage/emulated/0/oss/examplefile.txt. String localFilepath = "/storage/emulated/0/oss/examplefile.txt"; ObjectMetadata meta = new ObjectMetadata(); // Tetapkan metadata file. meta.setHeader("x-oss-object-acl", "public-read-write"); MultipartUploadRequest rq = new MultipartUploadRequest(bucketName, objectName, localFilepath, meta); // Tetapkan ukuran bagian. Ukuran bagian default adalah 256 KB. Ukuran minimum bagian adalah 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);Untuk scoped storage pada Android 10 atau versi lebih baru, Anda dapat menggunakan URI file untuk mengunggah file ke OSS.
// Tentukan nama bucket, misalnya examplebucket. String bucketName = "examplebucket"; // Tentukan path lengkap objek, misalnya exampledir/exampleobject.txt. Path lengkap objek tidak boleh mengandung nama bucket. String objectName = "exampledir/exampleobject.txt"; ObjectMetadata meta = new ObjectMetadata(); // Tetapkan metadata file. meta.setHeader("x-oss-object-acl", "public-read-write"); MultipartUploadRequest rq = new MultipartUploadRequest(bucketName, objectName, fileUri, meta); // Tetapkan ukuran bagian. Ukuran bagian default adalah 256 KB. Ukuran minimum bagian adalah 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);Panggil API asinkron untuk melakukan unggah multi-bagian file lokal
Kode berikut menunjukkan cara mengunggah file examplefile.txt secara asinkron ke folder exampledir dalam bucket examplebucket, menyimpannya sebagai objek exampleobject.txt.
// Tentukan nama bucket, misalnya examplebucket. String bucketName = "examplebucket"; // Tentukan path lengkap objek, misalnya exampledir/exampleobject.txt. Path lengkap objek tidak boleh mengandung nama bucket. String objectName = "exampledir/exampleobject.txt"; // Tentukan path lengkap file lokal, misalnya /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); // Batalkan unggah multi-bagian. //task.cancel(); task.waitUntilFinished();Untuk scoped storage pada Android 10 atau versi lebih baru, Anda dapat menggunakan URI file untuk mengunggah file ke OSS.
// Tentukan nama bucket, misalnya examplebucket. String bucketName = "examplebucket"; // Tentukan path lengkap objek, misalnya exampledir/exampleobject.txt. Path lengkap objek tidak boleh mengandung nama bucket. 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); // Batalkan unggah multi-bagian. //task.cancel(); task.waitUntilFinished();
Cantumkan bagian yang telah diunggah
Panggil metode oss.listParts untuk memperoleh semua bagian yang telah diunggah untuk event unggah multi-bagian tertentu.
Kode berikut menunjukkan cara mencantumkan bagian yang telah diunggah.
// Tentukan nama bucket, misalnya examplebucket.
String bucketName = "examplebucket";
// Tentukan path lengkap objek, misalnya exampledir/exampleobject.txt. Path lengkap objek tidak boleh mengandung nama bucket.
String objectName = "exampledir/exampleobject.txt";
// Tentukan uploadId. uploadId diperoleh dari respons setelah Anda memanggil InitiateMultipartUpload untuk menginisialisasi unggah multi-bagian dan sebelum memanggil CompleteMultipartUpload untuk menyelesaikan unggah multi-bagian.
String uploadId = "0004B999EF518A1FE585B0C9****";
// Cantumkan bagian.
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()));
}Secara default, jika suatu bucket berisi lebih dari 1.000 bagian yang diunggah menggunakan unggah multi-bagian, OSS mengembalikan 1.000 bagian pertama. Dalam respons, nilai bidang IsTruncated adalah false dan NextPartNumberMarker dikembalikan untuk menunjukkan posisi awal operasi pencantuman berikutnya.
Batalkan event unggah multi-bagian
Panggil metode oss.abortMultipartUpload untuk membatalkan event unggah multi-bagian. Setelah event tersebut dibatalkan, Anda tidak dapat lagi menggunakan uploadId-nya untuk operasi apa pun, dan bagian-bagian yang telah diunggah akan dihapus.
Kode berikut menunjukkan cara membatalkan event unggah multi-bagian.
// Tentukan nama bucket, misalnya examplebucket.
String bucketName = "examplebucket";
// Tentukan path lengkap objek, misalnya exampledir/exampleobject.txt. Path lengkap objek tidak boleh mengandung nama bucket.
String objectName = "exampledir/exampleobject.txt";
// Tentukan uploadId. uploadId diperoleh dari respons setelah Anda memanggil InitiateMultipartUpload untuk menginisialisasi unggah multi-bagian.
String uploadId = "0004B999EF518A1FE585B0C9****";
// Batalkan unggah multi-bagian.
AbortMultipartUploadRequest abort = new AbortMultipartUploadRequest(bucketName, objectName, uploadId);
AbortMultipartUploadResult abortResult = oss.abortMultipartUpload(abort);Referensi
Untuk kode contoh lengkap unggah multi-bagian, lihat GitHub.
Unggah multi-bagian melibatkan tiga operasi API. Untuk informasi selengkapnya tentang operasi tersebut, lihat topik berikut:
Untuk informasi selengkapnya tentang operasi API yang digunakan untuk membatalkan event unggah multi-bagian, lihat AbortMultipartUpload.
Untuk informasi selengkapnya tentang operasi API yang digunakan untuk mencantumkan bagian yang telah diunggah, lihat ListParts.
Untuk informasi selengkapnya tentang operasi API yang digunakan untuk mencantumkan semua event unggah multi-bagian yang sedang berlangsung (event yang telah diinisiasi tetapi belum diselesaikan atau dibatalkan), lihat ListMultipartUploads.
Untuk informasi lebih lanjut tentang cara menginisialisasi instance OSSClient, lihat Menginisialisasi instance OSSClient untuk Android.