全部产品
存储与CDN 数据库 安全 应用服务 数加·人工智能 数加·大数据基础服务 互联网中间件 视频服务 开发者工具 解决方案 物联网
对象存储 OSS

下载文件

更新时间:2017-07-12 09:13:39

OSS Java SDK提供了丰富的文件下载接口,用户可以通过以下方式从OSS中下载文件:

  • 流式下载
  • 下载到本地文件
  • 断点续传下载
  • 范围下载

流式下载

在进行大文件下载时,往往不希望一次性处理全部内容,而是希望流式地处理,一次处理一部分内容。

提示:

  • 流式下载的完整代码请参考:GitHub
  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. OSSObject ossObject = ossClient.getObject(bucketName, "yourKey");
  10. // 读Object内容
  11. System.out.println("Object content:");
  12. BufferedReader reader = new BufferedReader(new InputStreamReader(ossObject.getObjectContent()));
  13. while (true) {
  14. String line = reader.readLine();
  15. if (line == null) break;
  16. System.out.println("\n" + line);
  17. }
  18. reader.close();
  19. // 关闭client
  20. ossClient.shutdown();

提示:

  • OSSObject实例包含文件所在的存储空间(Bucket)、文件的名称、Object Metadata以及一个输入流;
  • 通过操作输入流将文件的内容读取到文件或者内存中。而Object Metadata包含ETag、HTTP Header及自定义的元信息;
  • OSSClient.getObject获取的流一定要显示close,否则会造成资源泄露;
    1. OSSObject ossObject = ossClient.getObject(bucketName, key);
    2. ossObject.getObjectContent().close();
  • 假如需要从OSS流式读取64KB的数据,请使用如下的方式多次读取,直到读取64KB或者文件结束:
    1. byte[] buf = new byte[1024];
    2. InputStream in = ossObject.getObjectContent();
    3. for (int n = 0; n != -1; ) {
    4. n = in.read(buf, 0, buf.length);
    5. }
    6. in.close();
    而不是如下的形式:
    1. byte[] buf = new byte[64 * 1024];
    2. InputStream in = ossObject.getObjectContent();
    3. in.read(buf, 0, buf.length);
    4. in.close();
    原因是,流式读取一次不一定能读到全部数据,详细说明请参考 InputStream.read

下载到本地文件

把Object的内容下载到指定的本地文件中。如果指定的本地文件不存在则会新建。

  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. // 下载object到文件
  10. ossClient.getObject(new GetObjectRequest(bucketName, "<yourKey>"), new File("<yourLocalFile>"));
  11. // 关闭client
  12. ossClient.shutdown();

范围下载

如果OSS文件较大,并且只需要其中一部分数据,可以使用范围下载,下载指定范围的数据。如果指定的下载范围是0 - 1000,则返回第0到第1000个字节的数据,包括第1000个,共1001字节的数据,即[0, 1000]。如果指定的范围无效,则传送整个文件。

  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 getObjectRequest = new GetObjectRequest(bucketName, "<yourKey>");
  10. // 获取0~1000字节范围内的数据,包括0和1000,共1001个字节的数据
  11. getObjectRequest.setRange(0, 1000);
  12. // 范围下载
  13. OSSObject ossObject = ossClient.getObject(getObjectRequest);
  14. // 读取数据
  15. byte[] buf = new byte[1024];
  16. InputStream in = ossObject.getObjectContent();
  17. for (int n = 0; n != -1; ) {
  18. n = in.read(buf, 0, buf.length);
  19. }
  20. // InputStream数据读完成后,一定要close,否则会造成连接泄漏
  21. in.close();
  22. // 关闭client
  23. ossClient.shutdown();

提示:

  • 如果指定的Range无效(比如开始位置、结束位置为负数,大于文件大小),则会下载整个文件;
  • 假如需要从OSS流式读取64KB的数据,请使用如下的方式多次读取,直到读取64KB或者文件结束:
    1. byte[] buf = new byte[1024];
    2. InputStream in = ossObject.getObjectContent();
    3. for (int n = 0; n != -1; ) {
    4. n = in.read(buf, 0, buf.length);
    5. }
    6. in.close();
    而不是如下的形式:
    1. byte[] buf = new byte[64 * 1024];
    2. InputStream in = ossObject.getObjectContent();
    3. in.read(buf, 0, buf.length);
    4. in.close();
    原因是,流式读取一次不一定能读到全部数据,详细说明请参考 InputStream.read

断点续传下载

当下载大文件时,如果网络不稳定或者程序崩溃了,则整个下载就失败了。用户不得不重头再来,这样做不仅浪费资源,在网络不稳定的情况下,往往重试多次还是无法完成下载。通过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不支持进度条功能。
本文导读目录