You need to enable JavaScript to run this app.
导航

断点续传下载(Android SDK)

最近更新时间2024.02.04 18:31:00

首次发布时间2022.12.01 16:31:40

下载大文件时,可以使用 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();
    }
}