O Object Storage Service (OSS) oferece um recurso de upload multipart para objetos grandes. Esse processo divide o objeto em partes menores, envia cada uma de forma independente e chama a API CompleteMultipartUpload para combiná-las em um único objeto, permitindo uploads retomáveis.
Observações de uso
Antes de executar o código de exemplo deste tópico, crie uma instância OSSClient por meio de métodos como nome de domínio personalizado ou Security Token Service (STS). Para obter mais informações, consulte Inicialização (Android SDK).
Processo de upload multipart
O upload multipart consiste nas três etapas a seguir:
-
Inicie um evento de upload multipart.
Chame o método oss.initMultipartUpload. O OSS retorna um uploadId globalmente exclusivo.
-
Envie as partes.
Chame o método oss.uploadPart para enviar cada parte.
NotaO número da parte identifica sua posição no objeto. O envio de dados com o mesmo número substitui a parte existente.
O OSS retorna o hash MD5 dos dados recebidos no cabeçalho ETag da resposta.
O OSS calcula o hash MD5 dos dados enviados e o compara com o hash calculado pelo SDK. Em caso de incompatibilidade, o sistema retorna o código de erro InvalidDigest.
-
Conclua o upload multipart.
Após enviar todas as partes, chame o método oss.CompleteMultipartUpload para combiná-las em um objeto completo.
Exemplo completo de upload multipart
O exemplo a seguir demonstra o processo completo de upload multipart:
// Specify the bucket name, for example, examplebucket.
String bucketName = "examplebucket";
// Specify the full path of the object, for 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, for example, /storage/emulated/0/oss/examplefile.txt.
String localFilepath = "/storage/emulated/0/oss/examplefile.txt";
// Initialize the multipart upload.
InitiateMultipartUploadRequest init = new InitiateMultipartUploadRequest(bucketName, objectName);
InitiateMultipartUploadResult initResult = oss.initMultipartUpload(init);
// The uploadId is returned.
String uploadId = initResult.getUploadId();
// Use the uploadId to cancel the multipart upload event or list the uploaded parts.
// To cancel the multipart upload event based on the uploadId, obtain the uploadId after you call InitiateMultipartUpload to initialize the multipart upload.
// To list the uploaded parts based on the uploadId, obtain the uploadId after you call InitiateMultipartUpload to initialize the multipart upload and before you call CompleteMultipartUpload to complete the multipart upload.
// Log.d("uploadId", uploadId);
// Set the size of a single part in bytes. The minimum size of a part is 100 KB, and the maximum size is 5 GB. The size of the last part can be less than 100 KB.
int partCount = 100 * 1024;
// Upload parts.
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);
// Set the part number, which starts from 1. Each uploaded part has a part number that ranges from 1 to 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;
}
}
});
// Complete the multipart upload.
CompleteMultipartUploadRequest complete = new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);
// Upload callback. When you complete the multipart upload request, you can set the CALLBACK_SERVER parameter. After the request is complete, a callback request is sent to the specified server address. You can view the server callback result from completeResult.getServerCallbackReturnBody() in the returned result.
complete.setCallbackParam(new HashMap<String, String>() {
{
put("callbackUrl", CALLBACK_SERVER); // Change the value to your server address.
put("callbackBody", "test");
}
});
CompleteMultipartUploadResult completeResult = oss.completeMultipartUpload(complete);
OSSLog.logError("-------------- serverCallback: " + completeResult.getServerCallbackReturnBody());
O código anterior chama uploadPart para enviar cada parte.
Cada solicitação de upload de parte deve especificar um uploadId e um partNumber. O valor de partNumber deve estar no intervalo de 1 a 10.000. Se estiver fora desse intervalo, o OSS retornará o código de erro InvalidArgument.
Ao chamar uploadPart, todas as partes, exceto a última, devem ser maiores que 100 KB. O OSS verifica o tamanho da parte apenas na conclusão do upload multipart.
Antes de enviar cada parte, posicione o stream no início dos dados correspondentes.
Após o envio de cada parte, a resposta do OSS contém um valor ETag, que corresponde ao hash MD5 dos dados dessa parte. Combine o valor ETag e o número da parte em um PartETag e salve-o para concluir o upload multipart.
Upload multipart de um arquivo local
É possível enviar um arquivo local para o OSS usando uma operação de upload multipart síncrona ou assíncrona.
A seção anterior fornece um exemplo completo que mostra o processo de upload multipart passo a passo. O código nesta seção encapsula esse processo para o upload de arquivos locais. Basta usar MultipartUploadRequest para realizar um upload multipart.
-
Enviar um arquivo local usando a operação de upload multipart síncrona
O código a seguir mostra como enviar de forma síncrona o arquivo examplefile.txt para o objeto exampleobject.txt na pasta exampledir do bucket examplebucket.
// Specify the bucket name, for example, examplebucket. String bucketName = "examplebucket"; // Specify the full path of the object, for 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, for example, /storage/emulated/0/oss/examplefile.txt. String localFilepath = "/storage/emulated/0/oss/examplefile.txt"; ObjectMetadata meta = new ObjectMetadata(); // Set file metadata. meta.setHeader("x-oss-object-acl", "public-read-write"); MultipartUploadRequest rq = new MultipartUploadRequest(bucketName, objectName, localFilepath, meta); // Set the part size. The default part size is 256 KB. The minimum part size 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);Para armazenamento com escopo no Android 10 ou posterior, use a URI do arquivo para enviá-lo ao OSS.
// Specify the bucket name, for example, examplebucket. String bucketName = "examplebucket"; // Specify the full path of the object, for example, exampledir/exampleobject.txt. The full path of the object cannot contain the bucket name. String objectName = "exampledir/exampleobject.txt"; ObjectMetadata meta = new ObjectMetadata(); // Set file metadata. meta.setHeader("x-oss-object-acl", "public-read-write"); MultipartUploadRequest rq = new MultipartUploadRequest(bucketName, objectName, fileUri, meta); // Set the part size. The default part size is 256 KB. The minimum part size 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); -
Chamar uma API assíncrona para realizar o upload multipart de um arquivo local
O código a seguir mostra como enviar de forma assíncrona o arquivo examplefile.txt para a pasta exampledir no bucket examplebucket, salvando-o como o objeto exampleobject.txt.
// Specify the bucket name, for example, examplebucket. String bucketName = "examplebucket"; // Specify the full path of the object, for 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, for 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.cancel(); task.waitUntilFinished();Para armazenamento com escopo no Android 10 ou posterior, use a URI do arquivo para enviá-lo ao OSS.
// Specify the bucket name, for example, examplebucket. String bucketName = "examplebucket"; // Specify the full path of the object, for 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.cancel(); task.waitUntilFinished();
Listar partes enviadas
Chame o método oss.listParts para obter todas as partes enviadas de um evento específico de upload multipart.
O código a seguir mostra como listar as partes enviadas.
// Specify the bucket name, for example, examplebucket.
String bucketName = "examplebucket";
// Specify the full path of the object, for example, exampledir/exampleobject.txt. The full path of the object cannot contain the bucket name.
String objectName = "exampledir/exampleobject.txt";
// Specify the uploadId. The uploadId is obtained from the response after you call InitiateMultipartUpload to initialize the multipart upload and before you call CompleteMultipartUpload to complete the multipart upload.
String uploadId = "0004B999EF518A1FE585B0C9****";
// List 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()));
}
Se existirem mais de 1.000 partes, o OSS retornará apenas as primeiras 1.000. Na resposta, IsTruncated é falso e NextPartNumberMarker indica onde começa a próxima listagem.
Cancelar um evento de upload multipart
Chame o método oss.abortMultipartUpload para cancelar um evento de upload multipart. Após o cancelamento, não é mais possível usar o uploadId correspondente para nenhuma operação. As partes já enviadas são excluídas.
O código a seguir mostra como cancelar um evento de upload multipart.
// Specify the bucket name, for example, examplebucket.
String bucketName = "examplebucket";
// Specify the full path of the object, for example, exampledir/exampleobject.txt. The full path of the object cannot contain the bucket name.
String objectName = "exampledir/exampleobject.txt";
// Specify the uploadId. The uploadId is obtained from the response after you call InitiateMultipartUpload to initialize the multipart upload.
String uploadId = "0004B999EF518A1FE585B0C9****";
// Cancel the multipart upload.
AbortMultipartUploadRequest abort = new AbortMultipartUploadRequest(bucketName, objectName, uploadId);
AbortMultipartUploadResult abortResult = oss.abortMultipartUpload(abort);
Referências
Para ver o código de exemplo completo de upload multipart, consulte GitHub.
-
Um upload multipart envolve três operações de API:
Inicializar um upload multipart: InitiateMultipartUpload.
Enviar uma parte: UploadPart.
Concluir um upload multipart: CompleteMultipartUpload.
Para obter mais informações sobre a operação de API usada para cancelar um evento de upload multipart, consulte AbortMultipartUpload.
Para obter mais informações sobre a operação de API usada para listar partes enviadas, consulte ListParts.
Para obter mais informações sobre a operação de API usada para listar todos os eventos de upload multipart em andamento (iniciados, mas ainda não concluídos ou cancelados), consulte ListMultipartUploads.
Para obter mais informações sobre como inicializar uma instância OSSClient, consulte Inicializar uma instância OSSClient para Android.