开发者社区 问答 正文

Java-SDK之如何实现下载文件(二)?


断点续传下载


当下载大文件时,如果网络不稳定或者程序崩溃了,则整个下载就失败了。用户不得不重头再来,这样做不仅浪费资源,在网络不稳定的情况下,往往重试多次还是无法完成下载。通过OSSClient.downloadFile接口来实现断点续传分片下载,参数是DownloadFileRequest,该请求有以下参数:

  • bucket 存储空间名字,必选参数,通过构造方法设置
  • key 下载到OSS的Object名字,必选参数,通过构造方法设置
  • downloadFile 本地文件,下载到该文件,可选参数,默认是key,通过构造方法或setDownloadFile设置
  • partSize 分片大小,从1B到5GB,单位是Byte,可选参数,默认100K,通过setPartSize设置
  • taskNum 分片下载并发数,可选参数,默认为1,通过setTaskNum设置
  • enableCheckpoint 下载是否开启断点续传,可选参数,默认断点续传功能关闭,通过setEnableCheckpoint设置
  • checkpointFile 开启断点续传时,需要在本地记录分片下载结果,如果下载失败,下次不会再下载已经成功的分片,可选参数,默认与downloadFile同目录,为downloadFile.ucp,可以通过setCheckpointFile设置

其实现的原理是将要下载的Object分成若干个分片分别下载,最后所有分片都下载成功后,完成整个文件的下载。在下载的过程中会记录当前下载的进度信息(记录在checkpoint文件中)和已下载的分片,如果下载过程中某一分片下载失败,再次下载时会从checkpoint文件中记录的点继续下载。这要求再次调用时要指定与上次相同的checkpoint文件。下载完成后,checkpoint文件会被删除。
  1. // endpoint以杭州为例,其它region请按实际情况填写
  2. String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
  3. // 云账号AccessKey有所有API访问权限,建议遵循阿里云安全最佳实践,创建并使用RAM子账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建
  4. String accessKeyId = "<yourAccessKeyId>";
  5. String accessKeySecret = "<yourAccessKeySecret>";
  6. String bucketName = "<yourBucketName>";
  7. // 创建OSSClient实例
  8. OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
  9. // 下载请求,10个任务并发下载,启动断点续传
  10. DownloadFileRequest downloadFileRequest = new DownloadFileRequest("bucketName", "key");
  11. downloadFileRequest.setDownloadFile("downloadFile");
  12. downloadFileRequest.setTaskNum(10);
  13. downloadFileRequest.setEnableCheckpoint(true);
  14. // 下载文件
  15. DownloadFileResult downloadRes = ossClient.downloadFile(downloadFileRequest);
  16. // 下载成功时,会返回文件的元信息
  17. downloadRes.getObjectMetadata();
  18. // 关闭client
  19. ossClient.shutdown();


限定条件下载


下载文件时,可以指定一个或多个限定条件,满足限定条件时下载,不满足时报错,不下载文件。可以使用的限定条件如下:
参数说明
If-Modified-Since如果指定的时间早于实际修改时间,则正常传送。否则返回错误。
If-Unmodified-Since如果传入参数中的时间等于或者晚于文件实际修改时间,则正常传输文件;否则返回错误。
If-Match如果传入期望的ETag和object的 ETag匹配,则正常传输;否则返回错误。
If-None-Match如果传入的ETag值和Object的ETag不匹配,则正常传输;否则返回错误。

注意:
  • 如果If-Modified-Since设定的时间不符合规范,直接返回文件,并返回200 OK;
  • If-Modified-Since和If-Unmodified-Since可以同时存在,If-Match和If-None-Match也可以同时存在;
  • 如果包含If-Unmodified-Since并且不符合或者包含If-Match并且不符合,返回412 precondition failed;
  • 如果包含If-Modified-Since并且不符合或者包含If-None-Match并且不符合,返回304 Not Modified。
  1. // endpoint以杭州为例,其它region请按实际情况填写
  2. String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
  3. // 云账号AccessKey有所有API访问权限,建议遵循阿里云安全最佳实践,创建并使用RAM子账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建
  4. String accessKeyId = "<yourAccessKeyId>";
  5. String accessKeySecret = "<yourAccessKeySecret>";
  6. String bucketName = "<yourBucketName>";
  7. // 创建OSSClient实例
  8. OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
  9. GetObjectRequest request = new GetObjectRequest(bucketName, "<yourKey>");
  10. request.setModifiedSinceConstraint(new Date());
  11. // 下载object到文件
  12. ossClient.getObject(request, new File("<yourLocalFile>"));
  13. // 关闭client
  14. ossClient.shutdown();

提示:
  • ETag的值可以通过OSSClient.getObjectMetadata获取;
  • OSSClient.getObject,OSSClient.downloadFile都支持限定条件。


下载进度条


OSS Java sdk支持进度条功能,指示上传/下载的进度。下面的代码以OSSClient.getObject为例,说明进度条功能的使用。

提示:
  • 下载进度条的完整代码请参考:GitHub
  1. static class GetObjectProgressListener implements ProgressListener {
  2.         private long bytesRead = 0;
  3.         private long totalBytes = -1;
  4.         private boolean succeed = false;
  5.         @Override
  6.         public void progressChanged(ProgressEvent progressEvent) {
  7.             long bytes = progressEvent.getBytes();
  8.             ProgressEventType eventType = progressEvent.getEventType();
  9.             switch (eventType) {
  10.             case TRANSFER_STARTED_EVENT:
  11.                 System.out.println("Start to download......");
  12.                 break;
  13.             case RESPONSE_CONTENT_LENGTH_EVENT:
  14.                 this.totalBytes = bytes;
  15.                 System.out.println(this.totalBytes + " bytes in total will be downloaded to a local file");
  16.                 break;
  17.             case RESPONSE_BYTE_TRANSFER_EVENT:
  18.                 this.bytesRead += bytes;
  19.                 if (this.totalBytes != -1) {
  20.                     int percent = (int)(this.bytesRead * 100.0 / this.totalBytes);
  21.                     System.out.println(bytes + " bytes have been read at this time, download progress: " +
  22.                             percent + "%(" + this.bytesRead + "/" + this.totalBytes + ")");
  23.                 } else {
  24.                     System.out.println(bytes + " bytes have been read at this time, download ratio: unknown" +
  25.                             "(" + this.bytesRead + "/...)");
  26.                 }
  27.                 break;
  28.             case TRANSFER_COMPLETED_EVENT:
  29.                 this.succeed = true;
  30.                 System.out.println("Succeed to download, " + this.bytesRead + " bytes have been transferred in total");
  31.                 break;
  32.             case TRANSFER_FAILED_EVENT:
  33.                 System.out.println("Failed to download, " + this.bytesRead + " bytes have been transferred");
  34.                 break;
  35.             default:
  36.                 break;
  37.             }
  38.         }
  39.         public boolean isSucceed() {
  40.             return succeed;
  41.         }
  42.     }
  43. public static void main(String[] args) {
  44.     String endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
  45.     String accessKeyId = "<accessKeyId>";
  46.     String accessKeySecret = "<accessKeySecret>";
  47.     String bucketName = "<bucketName>";
  48.     String key = "object-get-progress-sample";
  49.     OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
  50.     try {            
  51.             // 带进度条的下载
  52.             client.getObject(new GetObjectRequest(bucketName, key).
  53.                     <GetObjectRequest>withProgressListener(new GetObjectProgressListener()),
  54.                     new File("<yourLocalFile>"));
  55.     } catch (Exception e) {
  56.         e.printStackTrace();
  57.     }
  58.     ossClient.shutdown();
  59. }

提示:
  • putObject/getObject/uploadPart都支持进度条功能;
  • uploadFile/downloadFile不支持进度条功能。


展开
收起
青衫无名 2017-10-18 10:51:49 4617 分享 版权
0 条回答
写回答
取消 提交回答