private DownloadFileResult downloadFileWithCheckpoint(DownloadFileRequest downloadFileRequest)
      throws Throwable {
    DownloadFileResult downloadFileResult = new DownloadFileResult();
    DownloadCheckPoint downloadCheckPoint = new DownloadCheckPoint();

    // 开启断点续传,从checkpoint文件读取上次分片下载的结果
    if (downloadFileRequest.isEnableCheckpoint()) {
      // 从checkpoint文件读取上次下载结果,checkpoint文件不存在/文件被篡改/被破坏时,从新下载
      try {
        downloadCheckPoint.load(downloadFileRequest.getCheckpointFile());
      } catch (Exception e) {
        remove(downloadFileRequest.getCheckpointFile());
      }

      // 上传的文件修改了,从新下载
      if (!downloadCheckPoint.isValid(objectOperation)) {
        prepare(downloadCheckPoint, downloadFileRequest);
        remove(downloadFileRequest.getCheckpointFile());
      }
    } else {
      // 没有开启断点下载功能,从新下载
      prepare(downloadCheckPoint, downloadFileRequest);
    }

    // 并发下载分片
    DownloadResult downloadResult = download(downloadCheckPoint, downloadFileRequest);
    for (PartResult partResult : downloadResult.getPartResults()) {
      if (partResult.isFailed()) {
        throw partResult.getException();
      }
    }

    // 开启了断点下载,成功上传后删除checkpoint文件
    if (downloadFileRequest.isEnableCheckpoint()) {
      remove(downloadFileRequest.getCheckpointFile());
    }

    downloadFileResult.setObjectMetadata(downloadResult.getObjectMetadata());
    return downloadFileResult;
  }
  private void prepare(
      DownloadCheckPoint downloadCheckPoint, DownloadFileRequest downloadFileRequest)
      throws IOException {
    downloadCheckPoint.magic = DownloadCheckPoint.DOWNLOAD_MAGIC;
    downloadCheckPoint.downloadFile = downloadFileRequest.getDownloadFile();
    downloadCheckPoint.bucketName = downloadFileRequest.getBucketName();
    downloadCheckPoint.objectKey = downloadFileRequest.getKey();
    downloadCheckPoint.objectStat =
        ObjectStat.getFileStat(
            objectOperation, downloadCheckPoint.bucketName, downloadCheckPoint.objectKey);
    downloadCheckPoint.downloadParts =
        splitFile(downloadCheckPoint.objectStat.size, downloadFileRequest.getPartSize());

    createFixedFile(downloadFileRequest.getDownloadFile(), downloadCheckPoint.objectStat.size);
  }