在无线网络下,上传比较大的文件持续时间长,可能会遇到因为网络条件差、用户切换网络等原因导致上传中途失败,整个文件需要重新上传。为此,Android SDK提供了断点续传上传功能。

背景信息

对于移动端来说,如果不是大文件(例如小于5 GB的文件),不建议使用此种方式上传。断点续传上传是通过分片上传实现的,上传单个文件需要进行多次网络请求,效率不高。以下介绍断点续传上传前以及断点续传上传过程中的注意事项。

  • 断点续传上传前

    通过断点续传上传的方式将文件上传到OSS前,您可以指定断点记录的保存文件夹。断点续传上传仅在本次上传生效。

    • 如果未指定断点记录的保存文件夹,假设某个分片因为网络原因等导致文件上传失败时,将耗用大量的重试时间及流量来重新上传整个大文件。
    • 如果指定了断点记录的保存文件夹,在文件上传失败时,将从断点记录处继续上传未上传完成的部分。
  • 断点续传上传时

    使用断点续传上传时,您需要了解以下信息。

    • 断点续传上传仅支持上传本地文件。断点续传上传支持上传回调,使用方法与常见的上传回调类似,详情请参见Callback
    • 断点续传上传依赖InitMultipartUploadUploadPartListPartsCompleteMultipartUploadAbortMultipartUpload等接口来实现。如果您需要通过STS鉴权模式来使用断点续传上传,则需要保证您拥有访问上述API接口的权限。
    • 断点续传上传默认已开启每个分片上传时的MD5校验,因此无需在request中设置Content-Md5头部。
    • 如果同一任务一直得不到续传,可能会在OSS上积累无用碎片。此时,您可以为Bucket设置lifeCycle规则的方式来定时清理碎片,详情请参见生命周期管理

示例代码

以下为断点续传上传的常见示例。

  • 断点记录不在本地持久保存时,调用ResumableUploadRequest方法实现断点续传上传的过程如下:
    // 创建断点上传请求。
    // objectKey等同于objectName,表示断点上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
    ResumableUploadRequest request = new ResumableUploadRequest("<bucketName>", "<objectKey>", "<uploadFilePath>");
    // 设置上传过程回调。
    request.setProgressCallback(new OSSProgressCallback<ResumableUploadRequest>() {
        @Override
        public void onProgress(ResumableUploadRequest request, long currentSize, long totalSize) {
            Log.d("resumableUpload", "currentSize: " + currentSize + " totalSize: " + totalSize);
        }
    });
    // 异步调用断点上传。
    OSSAsyncTask resumableTask = oss.asyncResumableUpload(request, new OSSCompletedCallback<ResumableUploadRequest, ResumableUploadResult>() {
        @Override
        public void onSuccess(ResumableUploadRequest request, ResumableUploadResult result) {
            Log.d("resumableUpload", "success!");
        }
    
        @Override
        public void onFailure(ResumableUploadRequest request, ClientException clientExcepion, ServiceException serviceException) {
            // 异常处理。
        }
    });
    
    // 等待完成断点上传任务。
    resumableTask.waitUntilFinished(); 
    					
  • 断点记录在本地持久保存时,调用ResumableUploadRequest方法实现断点续传上传的过程如下:
    String recordDirectory = Environment.getExternalStorageDirectory().getAbsolutePath() + "/oss_record/";
    
    File recordDir = new File(recordDirectory);
    
    // 确保断点记录的保存文件夹已存在,如果不存在则新建断点记录的保存文件夹。
    if (!recordDir.exists()) {
        recordDir.mkdirs();
    }
    
    // 创建断点上传请求,并指定断点记录文件的保存路径,保存路径为断点记录文件的绝对路径。
    ResumableUploadRequest request = new ResumableUploadRequest("<bucketName>", "<objectKey>", "<uploadFilePath>", recordDirectory);
    // 设置上传回调。
    request.setProgressCallback(new OSSProgressCallback<ResumableUploadRequest>() {
        @Override
        public void onProgress(ResumableUploadRequest request, long currentSize, long totalSize) {
            Log.d("resumableUpload", "currentSize: " + currentSize + " totalSize: " + totalSize);
        }
    });
    
    
    OSSAsyncTask resumableTask = oss.asyncResumableUpload(request, new OSSCompletedCallback<ResumableUploadRequest, ResumableUploadResult>() {
        @Override
        public void onSuccess(ResumableUploadRequest request, ResumableUploadResult result) {
            Log.d("resumableUpload", "success!");
        }
    
        @Override
        public void onFailure(ResumableUploadRequest request, ClientException clientExcepion, ServiceException serviceException) {
            // 异常处理。
        }
    });
    
    // 等待完成断点上传任务。
    resumableTask.waitUntilFinished();                
  • 断点续传上传的完整示例代码如下:
    String recordDirectory = Environment.getExternalStorageDirectory().getAbsolutePath() + "/oss_record/";
    
    File recordDir = new File(recordDirectory);
    
    // 确保断点记录的保存文件夹已存在,如果不存在则新建断点记录的保存文件夹。
    if (!recordDir.exists()) {
        recordDir.mkdirs();
    }
    
    // 创建断点续传上传请求,并指定断点记录文件的保存路径,保存路径为断点记录文件的绝对路径。
    ResumableUploadRequest request = new ResumableUploadRequest("<bucketName>", "<objectKey>", "<uploadFilePath>", recordDirectory);
    // 调用OSSAsyncTask cancel()方法时,DeleteUploadOnCancelling设置为false时,则不删除断点记录文件。如果不设置此参数,则默认值为true,表示删除断点记录文件,下次再上传用一个文件时则重新上传。
    request.setDeleteUploadOnCancelling(false);
    // 设置上传回调。
    request.setProgressCallback(new OSSProgressCallback<ResumableUploadRequest>() {
        @Override
        public void onProgress(ResumableUploadRequest request, long currentSize, long totalSize) {
            Log.d("resumableUpload", "currentSize: " + currentSize + " totalSize: " + totalSize);
        }
    });
    
    
    OSSAsyncTask resumableTask = oss.asyncResumableUpload(request, new OSSCompletedCallback<ResumableUploadRequest, ResumableUploadResult>() {
        @Override
        public void onSuccess(ResumableUploadRequest request, ResumableUploadResult result) {
            Log.d("resumableUpload", "success!");
        }
    
        @Override
        public void onFailure(ResumableUploadRequest request, ClientException clientExcepion, ServiceException serviceException) {
            // 异常处理。
        }
    });
    
    // 等待完成断点上传任务。
    resumableTask.waitUntilFinished();