下载大对象时,可能出现网络波动等情况导致下载失败。TOS Java SDK 提供了重试机制保障下载对象的稳定性,但仍可能出现多次重试后仍无法完成下载的情况。针对上述问题,Java SDK 提供了断点续传下载的功能,在大对象下载过程中如果出现下载失败,可再次调用接口,从上次下载的进度处继续下载。使用 Java SDK 的断点续传接口时,您可以自定义设置分片大小、下载的并发线程数、下载的客户端限速、事件回调函数等,也支持在断点续传下载任务执行过程中,取消该任务。
tos:GetObject
权限,具体操作,请参见权限配置指南。tos:GetObjectVersion
权限,具体操作,请参见权限配置指南。以下代码展示 SDK 断点续传下载接口 downloadFile
的基本使用方式。
import com.volcengine.tos.TOSV2; import com.volcengine.tos.TOSV2ClientBuilder; import com.volcengine.tos.TosClientException; import com.volcengine.tos.TosServerException; import com.volcengine.tos.model.object.DownloadFileInput; import com.volcengine.tos.model.object.DownloadFileOutput; public class DownloadFileExample { public static void main(String[] args) { String endpoint = "your endpoint"; String region = "your region"; String accessKey = System.getenv("TOS_ACCESS_KEY"); String secretKey = System.getenv("TOS_SECRET_KEY"); String bucketName = "bucket-example"; // 对象名,如果对象名以 "/"(linux 或 macOS 系统) 或 "\"(Windows 系统)结尾,将在本地生成对应空文件夹 String objectKey = "example_dir/example_object.txt"; // downloadFilePath 设置待下载的文件路径,建议使用绝对路径,确保路径下不存在文件,否则会将其覆盖。 String downloadFilePath = "example_dir/example_file.txt"; // taskNum 设置并发上传的并发数,范围为 1-1000 int taskNum = 5; // partSize 设置文件分片大小,范围为 5MB - 5GB,默认为 20MB long partSize = 10 * 1024 * 1024; // enableCheckpoint 设置是否开启断点续传功能,开启则会在本地记录上传进度 boolean enableCheckpoint = true; // checkpointFilePath 设置断点续传记录文件存放位置,若不设置则默认在 downloadFilePath 路径下生成 // 其格式为 {downloadFilePath}.{bucket+objectKey+versionID 的 Base64Md5 值}.download String checkpointFilePath = "the checkpoint file path"; TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey); try{ DownloadFileInput input = new DownloadFileInput().setBucket(bucketName).setKey(objectKey) .setFilePath(downloadFilePath).setEnableCheckpoint(enableCheckpoint) .setCheckpointFile(checkpointFilePath).setPartSize(partSize).setTaskNum(taskNum); DownloadFileOutput output = tos.downloadFile(input); System.out.println("downloadFile succeed, object's etag is " + output.getEtag()); System.out.println("downloadFile succeed, object's crc64 is " + output.getHashCrc64ecma()); } catch (TosClientException e) { // 操作失败,捕获客户端异常,一般情况是请求参数错误,此时请求并未发送 System.out.println("downloadFile failed"); System.out.println("Message: " + e.getMessage()); if (e.getCause() != null) { e.getCause().printStackTrace(); } } catch (TosServerException e) { // 操作失败,捕获服务端异常,可以获取到从服务端返回的详细错误信息 System.out.println("downloadFile failed"); System.out.println("StatusCode: " + e.getStatusCode()); System.out.println("Code: " + e.getCode()); System.out.println("Message: " + e.getMessage()); System.out.println("RequestID: " + e.getRequestID()); } catch (Throwable t) { // 作为兜底捕获其他异常,一般不会执行到这里 System.out.println("downloadFile failed"); System.out.println("unexpected exception, message: " + t.getMessage()); } } }
以下代码展示如何在断点续传下载过程中自定义监听回调函数。
import com.volcengine.tos.TOSV2; import com.volcengine.tos.TOSV2ClientBuilder; import com.volcengine.tos.TosClientException; import com.volcengine.tos.TosServerException; import com.volcengine.tos.comm.event.DownloadEventType; import com.volcengine.tos.model.object.*; public class DownloadFileWithEventListenerExample { public static void main(String[] args) { String endpoint = "your endpoint"; String region = "your region"; String accessKey = System.getenv("TOS_ACCESS_KEY"); String secretKey = System.getenv("TOS_SECRET_KEY"); String bucketName = "bucket-example"; // 对象名,如果对象名以 "/"(linux 或 macOS 系统) 或 "\"(Windows 系统)结尾,将在本地生成对应空文件夹 String objectKey = "example_dir/example_object.txt"; // downloadFilePath 设置待下载的文件路径,建议使用绝对路径,确保路径下不存在文件,否则会将其覆盖。 String downloadFilePath = "example_dir/example_file.txt"; // taskNum 设置并发上传的并发数,范围为 1-1000 int taskNum = 5; // partSize 设置文件分片大小,范围为 5MiB - 5GiB,默认为 20MiB long partSize = 10 * 1024 * 1024; // enableCheckpoint 设置是否开启断点续传功能,开启则会在本地记录上传进度 boolean enableCheckpoint = true; // checkpointFilePath 设置断点续传记录文件存放位置,若不设置则默认在 downloadFilePath 路径下生成 // 其格式为 {downloadFilePath}.{bucket+objectKey+versionID 的 Base64Md5 值}.download String checkpointFilePath = "the checkpoint file path"; TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey); try{ HeadObjectV2Input head = new HeadObjectV2Input().setBucket(bucketName).setKey(objectKey); DownloadEventListener listener = new DownloadEventListener() { @Override public void eventChange(DownloadEvent downloadEvent) { if (downloadEvent.getDownloadEventType() == DownloadEventType.DownloadEventCreateTempFileSucceed) { System.out.println("event change, createTempFile succeed"); } if (downloadEvent.getDownloadEventType() == DownloadEventType.DownloadEventCreateTempFileFailed) { System.out.println("event change, createTempFile failed"); } if (downloadEvent.getDownloadEventType() == DownloadEventType.DownloadEventDownloadPartSucceed) { System.out.println("event change, downloadPart succeed"); } if (downloadEvent.getDownloadEventType() == DownloadEventType.DownloadEventDownloadPartFailed) { System.out.println("event change, downloadPart failed"); } if (downloadEvent.getDownloadEventType() == DownloadEventType.DownloadEventDownloadPartAborted) { System.out.println("event change, downloadPart aborted"); } if (downloadEvent.getDownloadEventType() == DownloadEventType.DownloadEventRenameTempFileSucceed) { System.out.println("event change, renameTempFile succeed"); } if (downloadEvent.getDownloadEventType() == DownloadEventType.DownloadEventRenameTempFileFailed) { System.out.println("event change, renameTempFile failed"); } } }; DownloadFileInput input = new DownloadFileInput().setHeadObjectV2Input(head) .setFilePath(downloadFilePath).setEnableCheckpoint(enableCheckpoint) .setCheckpointFile(checkpointFilePath).setPartSize(partSize).setTaskNum(taskNum) .setDownloadEventListener(listener); DownloadFileOutput output = tos.downloadFile(input); System.out.println("downloadFile succeed, object's etag is " + output.getEtag()); System.out.println("downloadFile succeed, object's crc64 is " + output.getHashCrc64ecma()); } catch (TosClientException e) { // 操作失败,捕获客户端异常,一般情况是请求参数错误,此时请求并未发送 System.out.println("downloadFile failed"); System.out.println("Message: " + e.getMessage()); if (e.getCause() != null) { e.getCause().printStackTrace(); } } catch (TosServerException e) { // 操作失败,捕获服务端异常,可以获取到从服务端返回的详细错误信息 System.out.println("downloadFile failed"); System.out.println("StatusCode: " + e.getStatusCode()); System.out.println("Code: " + e.getCode()); System.out.println("Message: " + e.getMessage()); System.out.println("RequestID: " + e.getRequestID()); } catch (Throwable t) { // 作为兜底捕获其他异常,一般不会执行到这里 System.out.println("downloadFile failed"); System.out.println("unexpected exception, message: " + t.getMessage()); } } }
断点续传过程中,SDK 支持取消下载任务。以下代码展示如何取消正在执行的断点续传下载任务。
import com.volcengine.tos.TOSV2; import com.volcengine.tos.TOSV2ClientBuilder; import com.volcengine.tos.TosClientException; import com.volcengine.tos.TosServerException; import com.volcengine.tos.comm.event.DownloadEventType; import com.volcengine.tos.model.object.*; public class DownloadFileWithCancelExample { public static void main(String[] args) { String endpoint = "your endpoint"; String region = "your region"; String accessKey = System.getenv("TOS_ACCESS_KEY"); String secretKey = System.getenv("TOS_SECRET_KEY"); String bucketName = "bucket-example"; // 对象名,如果对象名以 "/"(linux 或 macOS 系统) 或 "\"(Windows 系统)结尾,将在本地生成对应空文件夹 String objectKey = "example_dir/example_object.txt"; // downloadFilePath 设置待下载的文件路径,建议使用绝对路径,确保路径下不存在文件,否则会将其覆盖。 String downloadFilePath = "example_dir/example_file.txt"; // taskNum 设置并发上传的并发数,范围为 1-1000 int taskNum = 5; // partSize 设置文件分片大小,范围为 5MB - 5GB,默认为 20MB long partSize = 10 * 1024 * 1024; // enableCheckpoint 设置是否开启断点续传功能,开启则会在本地记录上传进度 boolean enableCheckpoint = true; // checkpointFilePath 设置断点续传记录文件存放位置,若不设置则默认在 downloadFilePath 路径下生成 // 其格式为 {downloadFilePath}.{bucket+objectKey+versionID 的 Base64Md5 值}.download String checkpointFilePath = "the checkpoint file path"; TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey); try{ HeadObjectV2Input head = new HeadObjectV2Input().setBucket(bucketName).setKey(objectKey); DownloadFileInput input = new DownloadFileInput().setHeadObjectV2Input(head) .setFilePath(downloadFilePath).setEnableCheckpoint(enableCheckpoint) .setCheckpointFile(checkpointFilePath).setPartSize(partSize).setTaskNum(taskNum); // 以下代码通过 DownloadEventListener 监听下载事件。 // 如果出现 DownloadEventDownloadPartFailed 事件,即有下载失败的分片时就终止下载任务。 // 以下代码仅作为示例,用户可根据业务需要进行使用。 boolean isAbort = true; DownloadEventListener listener = new DownloadEventListener() { @Override public void eventChange(DownloadEvent downloadEvent) { if (downloadEvent.getDownloadEventType() == DownloadEventType.DownloadEventDownloadPartFailed) { System.out.println("event change, uploadPart failed"); if (input.getCancelHook() != null) { // 调用 cancel 时,如果 isAbort 为 true,会终止断点续传,删除本地 checkpoint 文件, // 并清理本地已下载的临时文件。 // 如果 isAbort 为 false,只会暂停当前下载任务,再次调用 downloadFile 可从断点处继续下载。 input.getCancelHook().cancel(isAbort); } } } }; input.setCancelHook(true).setDownloadEventListener(listener); DownloadFileOutput output = tos.downloadFile(input); System.out.println("downloadFile succeed, object's etag is " + output.getEtag()); System.out.println("downloadFile succeed, object's crc64 is " + output.getHashCrc64ecma()); } catch (TosClientException e) { // 操作失败,捕获客户端异常,一般情况是请求参数错误,此时请求并未发送 System.out.println("downloadFile failed"); System.out.println("Message: " + e.getMessage()); if (e.getCause() != null) { e.getCause().printStackTrace(); } } catch (TosServerException e) { // 操作失败,捕获服务端异常,可以获取到从服务端返回的详细错误信息 System.out.println("downloadFile failed"); System.out.println("StatusCode: " + e.getStatusCode()); System.out.println("Code: " + e.getCode()); System.out.println("Message: " + e.getMessage()); System.out.println("RequestID: " + e.getRequestID()); } catch (Throwable t) { // 作为兜底捕获其他异常,一般不会执行到这里 System.out.println("downloadFile failed"); System.out.println("unexpected exception, message: " + t.getMessage()); } } }