下载大文件时,可以使用 downloadFile 断点续传下载接口,TOS SDK 可通过 Range 下载的方式分片并发下载大文件,并借助本地 checkpoint 的机制记录已下载成功的分片。当出现网络异常或机器故障等问题导致下载中断,可再次调用该接口以实现续传的效果。
以下代码展示如何断点续传下载大对象。
import android.os.Bundle; import android.util.Log; import androidx.appcompat.app.AppCompatActivity; import com.volcengine.tos.TOSV2; import com.volcengine.tos.TOSV2ClientBuilder; import com.volcengine.tos.TosException; import com.volcengine.tos.model.object.DownloadFileInput; import com.volcengine.tos.model.object.DownloadFileOutput; import com.volcengine.tos.model.object.HeadObjectV2Input; public class DownloadFileExample extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { String endpoint = "your endpoint"; String region = "your region"; String accessKey = "your access key"; String secretKey = "your secret key"; String securityToken = "your security token"; String bucketName = "your bucket name"; String objectKey = "your object key"; // downloadFilePath 设置待下载的文件路径,建议使用绝对路径,确保路径下不存在文件,否则会将其覆盖。 // 如果 objectKey 以 "/"(linux 或 macOS 系统) 或 "\"(Windows 系统)结尾,将在本地生成对应空文件夹 String downloadFilePath = "the path of file to download"; // 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"; super.onCreate(savedInstanceState); setContentView(R.layout.activity_display_message); TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey, securityToken); Thread tosThread = new Thread(new Runnable() { @Override public void run() { 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); DownloadFileOutput output = tos.downloadFile(input); Log.i("downloadFile", "downloadFile succeed, object's etag is " + output.getOutput().getHeadObjectBasicOutput().getEtag()); Log.i("downloadFile", "downloadFile succeed, object's crc64 is " + output.getOutput().getHeadObjectBasicOutput().getHashCrc64ecma()); } catch (TosException e) { Log.e("TosException","downloadFile failed"); e.printStackTrace(); } } }); tosThread.start(); } }
downloadFile 接口调用过程会发送创建临时文件、下载分片、重命名临时文件等事件,您可以传入自定义接口来监听下载的相关事件,并实现自定义的业务逻辑。
以下代码展示如何使用事件监听功能。
import android.os.Bundle; import android.util.Log; import androidx.appcompat.app.AppCompatActivity; import com.volcengine.tos.TOSV2; import com.volcengine.tos.TOSV2ClientBuilder; import com.volcengine.tos.TosException; import com.volcengine.tos.comm.event.DownloadEventType; import com.volcengine.tos.model.object.DownloadEvent; import com.volcengine.tos.model.object.DownloadEventListener; import com.volcengine.tos.model.object.DownloadFileInput; import com.volcengine.tos.model.object.DownloadFileOutput; import com.volcengine.tos.model.object.HeadObjectV2Input; public class DownloadFileWithEventListenerExample extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { String endpoint = "your endpoint"; String region = "your region"; String accessKey = "your access key"; String secretKey = "your secret key"; String securityToken = "your security token"; String bucketName = "your bucket name"; String objectKey = "your object key"; // downloadFilePath 设置待下载的文件路径,建议使用绝对路径,确保路径下不存在文件,否则会将其覆盖。 // 如果 objectKey 以 "/"(linux 或 macOS 系统) 或 "\"(Windows 系统)结尾,将在本地生成对应空文件夹 String downloadFilePath = "the path of file to download"; // 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"; super.onCreate(savedInstanceState); setContentView(R.layout.activity_display_message); TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey, securityToken); Thread tosThread = new Thread(new Runnable() { @Override public void run() { try{ HeadObjectV2Input head = new HeadObjectV2Input().setBucket(bucketName).setKey(objectKey); DownloadEventListener listener = new DownloadEventListener() { @Override public void eventChange(DownloadEvent downloadEvent) { if (downloadEvent.getDownloadEventType() == DownloadEventType.DownloadEventCreateTempFileSucceed) { Log.i("downloadFile", "event change, createTempFile succeed"); } if (downloadEvent.getDownloadEventType() == DownloadEventType.DownloadEventCreateTempFileFailed) { Log.i("downloadFile", "event change, createTempFile failed"); } if (downloadEvent.getDownloadEventType() == DownloadEventType.DownloadEventDownloadPartSucceed) { Log.i("downloadFile", "event change, downloadPart succeed"); } if (downloadEvent.getDownloadEventType() == DownloadEventType.DownloadEventDownloadPartFailed) { Log.i("downloadFile", "event change, downloadPart failed"); } if (downloadEvent.getDownloadEventType() == DownloadEventType.DownloadEventDownloadPartAborted) { Log.i("downloadFile", "event change, downloadPart aborted"); } if (downloadEvent.getDownloadEventType() == DownloadEventType.DownloadEventRenameTempFileSucceed) { Log.i("downloadFile", "event change, renameTempFile succeed"); } if (downloadEvent.getDownloadEventType() == DownloadEventType.DownloadEventRenameTempFileFailed) { Log.i("downloadFile", "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); Log.i("downloadFile", "downloadFile succeed, object's etag is " + output.getOutput().getHeadObjectBasicOutput().getEtag()); Log.i("downloadFile", "downloadFile succeed, object's crc64 is " + output.getOutput().getHeadObjectBasicOutput().getHashCrc64ecma()); } catch (TosException e) { Log.e("TosException","downloadFile failed"); e.printStackTrace(); } } }); tosThread.start(); } }
downloadFile 接口支持您主动暂停或取消断点续传任务。暂停断点续传任务会停止下载,再次调用 downloadFile 时可以从上次暂停的位置继续下载。取消断点续传任务会停止下载,删除本地的 checkpoint 文件和下载的临时文件,再次调用 downloadFile 时会重新开始上传。
以下代码展示如何暂停或取消断点续传。
import android.os.Bundle; import android.util.Log; import androidx.appcompat.app.AppCompatActivity; import com.volcengine.tos.TOSV2; import com.volcengine.tos.TOSV2ClientBuilder; import com.volcengine.tos.TosException; import com.volcengine.tos.comm.event.DownloadEventType; import com.volcengine.tos.model.object.DownloadEvent; import com.volcengine.tos.model.object.DownloadEventListener; import com.volcengine.tos.model.object.DownloadFileInput; import com.volcengine.tos.model.object.DownloadFileOutput; import com.volcengine.tos.model.object.HeadObjectV2Input; public class DownloadFileWithCancelExample extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { String endpoint = "your endpoint"; String region = "your region"; String accessKey = "your access key"; String secretKey = "your secret key"; String securityToken = "your security token"; String bucketName = "your bucket name"; String objectKey = "your object key"; // downloadFilePath 设置待下载的文件路径,建议使用绝对路径,确保路径下不存在文件,否则会将其覆盖。 // 如果 objectKey 以 "/"(linux 或 macOS 系统) 或 "\"(Windows 系统)结尾,将在本地生成对应空文件夹 String downloadFilePath = "the path of file to download"; // 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"; super.onCreate(savedInstanceState); setContentView(R.layout.activity_display_message); TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey, securityToken); Thread tosThread = new Thread(new Runnable() { @Override public void run() { 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) { Log.i("downloadFile", "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); Log.i("downloadFile", "downloadFile succeed, object's etag is " + output.getOutput().getHeadObjectBasicOutput().getEtag()); Log.i("downloadFile", "downloadFile succeed, object's crc64 is " + output.getOutput().getHeadObjectBasicOutput().getHashCrc64ecma()); } catch (TosException e) { Log.e("TosException","downloadFile failed"); e.printStackTrace(); } } }); tosThread.start(); } }