public DownloadFileResult downloadFile(DownloadFileRequest downloadFileRequest) throws Throwable {
    assertParameterNotNull(downloadFileRequest, "downloadFileRequest");

    String bucketName = downloadFileRequest.getBucketName();
    String key = downloadFileRequest.getKey();

    assertParameterNotNull(bucketName, "bucketName");
    assertParameterNotNull(key, "key");
    ensureBucketNameValid(bucketName);
    ensureObjectKeyValid(key);

    // 没有指定本地文件,使用key作为本地文件名称
    if (downloadFileRequest.getDownloadFile() == null) {
      downloadFileRequest.setDownloadFile(downloadFileRequest.getKey());
    }

    // 开启断点续传,没有指定checkpoint文件,使用默认值
    if (downloadFileRequest.isEnableCheckpoint()) {
      if (downloadFileRequest.getCheckpointFile() == null
          || downloadFileRequest.getCheckpointFile().isEmpty()) {
        downloadFileRequest.setCheckpointFile(downloadFileRequest.getDownloadFile() + ".dcp");
      }
    }

    return downloadFileWithCheckpoint(downloadFileRequest);
  }
  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);
  }
  private DownloadResult download(
      DownloadCheckPoint downloadCheckPoint, DownloadFileRequest downloadFileRequest)
      throws Throwable {
    DownloadResult downloadResult = new DownloadResult();
    ArrayList<PartResult> taskResults = new ArrayList<PartResult>();
    ExecutorService service = Executors.newFixedThreadPool(downloadFileRequest.getTaskNum());
    ArrayList<Future<PartResult>> futures = new ArrayList<Future<PartResult>>();
    List<Task> tasks = new ArrayList<Task>();

    for (int i = 0; i < downloadCheckPoint.downloadParts.size(); i++) {
      if (!downloadCheckPoint.downloadParts.get(i).isCompleted) {
        Task task =
            new Task(
                i, "download-" + i, downloadCheckPoint, i, downloadFileRequest, objectOperation);
        futures.add(service.submit(task));
        tasks.add(task);
      } else {
        taskResults.add(
            new PartResult(
                i + 1,
                downloadCheckPoint.downloadParts.get(i).start,
                downloadCheckPoint.downloadParts.get(i).end));
      }
    }
    service.shutdown();

    service.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);

    for (Future<PartResult> future : futures) {
      try {
        PartResult tr = future.get();
        taskResults.add(tr);
      } catch (ExecutionException e) {
        throw e.getCause();
      }
    }

    Collections.sort(
        taskResults,
        new Comparator<PartResult>() {
          @Override
          public int compare(PartResult p1, PartResult p2) {
            return p1.getNumber() - p2.getNumber();
          }
        });

    downloadResult.setPartResults(taskResults);
    if (tasks.size() > 0) {
      downloadResult.setObjectMetadata(tasks.get(0).GetobjectMetadata());
    }

    return downloadResult;
  }
  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;
  }