全部產品
Search
文件中心

Object Storage Service:斷點續傳下載

更新時間:Jun 19, 2024

在下載OSS大檔案(超過5 GB)到本地的過程中,如果出現網路中斷、程式異常退出等問題導致檔案下載失敗,甚至重試多次仍無法完成下載,您需要使用斷點續傳下載的方式。斷點續傳下載將需要下載的大檔案分成多個較小的分區並發下載,加速下載完成時間。如果下載過程中,某一分區下載失敗,再次下載時會從Checkpoint檔案記錄的斷點繼續下載,無需重新下載所有分區。下載完成後,所有分區將合并成完整的檔案。

前提條件

  • 已上傳檔案到OSS。具體操作,請參見上傳檔案

  • 如果要下載Archive Storage類型的Object,請確保該Object已進入解凍狀態或Bucket已開啟歸檔直讀。具體操作,請參見解凍Object歸檔直讀

  • 如果要下載冷Archive Storage或者深度冷Archive Storage類型的Object,請確保該Object已進入解凍狀態。具體操作,請參見解凍Object

  • 已具有oss:GetObject許可權。具體操作,請參見RAM Policy常見樣本

注意事項

當前僅支援通過SDK的方式實現斷點續傳下載,斷點續傳下載過程中有以下注意事項:

  • 本文以華東1(杭州)外網Endpoint為例。如果您希望通過與OSS同地區的其他阿里雲產品訪問OSS,請使用內網Endpoint。關於OSS支援的Region與Endpoint的對應關係,請參見訪問網域名稱和資料中心

  • 本文以從環境變數讀取存取憑證為例。如何配置訪問憑證,請參見配置訪問憑證

  • 本文以OSS網域名稱建立OSSClient為例。如果您希望通過自訂網域名、STS等方式建立OSSClient,請參見初始化

  • 要斷點續傳下載,您必須有oss:GetObject許可權。具體操作,請參見為RAM使用者授權自訂的權限原則

  • SDK會將下載的狀態資訊記錄在Checkpoint檔案中,所以要確保程式對Checkpoint檔案有寫入權限。

  • 請勿修改Checkpoint檔案中攜帶的校正資訊。如果Checkpoint檔案損壞,則會重新下載所有分區。

  • 如果下載過程中檔案的ETag發生變化、Part丟失或被修改,則重新下載檔案。

使用阿里雲SDK

以下僅列舉常見SDK的斷點續傳下載的程式碼範例。關於其他SDK的斷點續傳下載的程式碼範例,請參見SDK簡介

import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;

public class Demo {
    public static void main(String[] args) throws Exception {
        // Endpoint以華東1(杭州)為例,其它Region請按實際情況填寫。
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填寫Bucket名稱,例如examplebucket。
        String bucketName = "examplebucket";
        // 填寫Object完整路徑,例如exampledir/exampleobject.txt。Object完整路徑中不能包含Bucket名稱。
        String objectName = "exampledir/exampleobject.txt";

        // 建立OSSClient執行個體。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
      	try {
            // 請求10個任務並發下載。
            DownloadFileRequest downloadFileRequest = new DownloadFileRequest(bucketName, objectName);
            // 指定Object下載到本地檔案的完整路徑,例如D:\\localpath\\examplefile.txt。
            downloadFileRequest.setDownloadFile("D:\\localpath\\examplefile.txt");
            // 設定分區大小,單位為位元組,取值範圍為100 KB~5 GB。預設值為100 KB。
            downloadFileRequest.setPartSize(1 * 1024 * 1024);
            // 設定分區下載的並發數,預設值為1。
            downloadFileRequest.setTaskNum(10);
            // 開啟斷點續傳下載,預設關閉。
            downloadFileRequest.setEnableCheckpoint(true);
            // 設定斷點記錄檔案的完整路徑,例如D:\\localpath\\examplefile.txt.dcp。
            // 只有當Object下載中斷產生了斷點記錄檔案後,如果需要繼續下載該Object,才需要設定對應的斷點記錄檔案。下載完成後,該檔案會被刪除。
            //downloadFileRequest.setCheckpointFile("D:\\localpath\\examplefile.txt.dcp");

            // 下載檔案。
            DownloadFileResult downloadRes = ossClient.downloadFile(downloadFileRequest);
            // 下載成功時,會返迴文件中繼資料。
            ObjectMetadata objectMetadata = downloadRes.getObjectMetadata();
            System.out.println(objectMetadata.getETag());
            System.out.println(objectMetadata.getLastModified());
            System.out.println(objectMetadata.getUserMetadata().get("meta"));
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (Throwable ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}
# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
# 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider())
# yourEndpoint填寫Bucket所在地區對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。
# 填寫Bucket名稱,例如examplebucket。
bucket = oss2.Bucket(auth, 'https://oss-cn-hangzhou.aliyuncs.com', 'examplebucket')

# yourObjectName填寫Object完整路徑,完整路徑中不能包含Bucket名稱,例如exampledir/exampleobject.txt。
# yourLocalFile填寫本地檔案的完整路徑,例如D:\\localpath\\examplefile.txt。
oss2.resumable_download(bucket, 'exampledir/exampleobject.txt', 'D:\\localpath\\examplefile.txt')
# 如未使用參數store指定目錄,則會在HOME目錄下建立.py-oss-upload目錄來儲存斷點資訊。

# Python SDK 2.1.0以上版本支援斷點續傳下載時設定以下選擇性參數。
# import sys
# # 當無法確定待下載的資料長度時,total_bytes的值為None。
# def percentage(consumed_bytes, total_bytes):
#     if total_bytes:
#         rate = int(100 * (float(consumed_bytes) / float(total_bytes)))
#         print('\r{0}% '.format(rate), end='')
#         sys.stdout.flush()
# # 如果使用store指定了目錄,則斷點資訊將儲存在指定目錄中。如果使用num_threads設定並發下載線程數,請將oss2.defaults.connection_pool_size設定為大於或等於並發下載線程數。預設並發下載線程數為1。
# oss2.resumable_download(bucket,  'exampledir/exampleobject.txt', 'D:\\localpath\\examplefile.txt',
#                       store=oss2.ResumableDownloadStore(root='/tmp'),
#                       # 指定當檔案長度大於或等於選擇性參數multipart_threshold(預設值為10 MB)時,則使用斷點續傳下載。
#                       multiget_threshold=100*1024,
#                       # 設定分區大小,單位為位元組,取值範圍為100 KB~5 GB。預設值為100 KB。
#                       part_size=100*1024,
#                       # 設定下載進度回呼函數。
#                       progress_callback=percentage,
#                       # 如果使用num_threads設定並發下載線程數,請將oss2.defaults.connection_pool_size設定為大於或等於並發下載線程數。預設並發下載線程數為1。
#                       num_threads=4)
using Aliyun.OSS;
using Aliyun.OSS.Common;

// yourEndpoint填寫Bucket所在地區對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。
var endpoint = "yourEndpoint";
// 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
// 填寫Bucket名稱,例如examplebucket。
var bucketName = "examplebucket";
// 填寫Object完整路徑,完整路徑中不能包含Bucket名稱,例如exampledir/exampleobject.txt。
var objectName = "exampleobject.txt";
// 下載Object到本地檔案examplefile.txt,並儲存到指定的本地路徑中(D:\\localpath)。如果指定的本地檔案存在會覆蓋,不存在則建立。
// 如果未指定本地路徑,則下載後的檔案預設儲存到樣本程式所屬專案對應本地路徑中。
var downloadFilename = "D:\\localpath\\examplefile.txt";
// 設定斷點記錄檔案的完整路徑,例如D:\\localpath\\examplefile.txt.dcp。
// 只有當Object下載中斷產生了斷點記錄檔案後,如果需要繼續下載該Object,才需要設定對應的斷點記錄檔案。下載完成後,該檔案會被刪除。
var checkpointDir = "D:\\localpath\\examplefile.txt.dcp";
// 建立OssClient執行個體。
var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
try
{
    // 通過DownloadObjectRequest設定多個參數。
    DownloadObjectRequest request = new DownloadObjectRequest(bucketName, objectName, downloadFilename)
    {
        // 指定下載的分區大小,單位為位元組。
        PartSize = 8 * 1024 * 1024,
        // 指定並發線程數。
        ParallelThreadCount = 3,
        // checkpointDir用於儲存斷點續傳進度資訊。如果某一分區下載失敗,再次下載時會根據檔案中記錄的點繼續下載。如果checkpointDir為null,斷點續傳功能不會生效,每次失敗後都會重新下載。
        CheckpointDir = checkpointDir,
    };
    // 斷點續傳下載。
    client.ResumableDownloadObject(request);
    Console.WriteLine("Resumable download object:{0} succeeded", objectName);
}
catch (OssException ex)
{
    Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
        ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
}
catch (Exception ex)
{
    Console.WriteLine("Failed with error info: {0}", ex.Message);
}
package main

import (
    "fmt"
    "os"
    "github.com/aliyun/aliyun-oss-go-sdk/oss"
)

func main() {
    /// 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
    provider, err := oss.NewEnvironmentVariableCredentialsProvider()
    if err != nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }

    // 建立OSSClient執行個體。
    // yourEndpoint填寫Bucket對應的Endpoint,以華東1(杭州)為例,填寫為https://oss-cn-hangzhou.aliyuncs.com。其它Region請按實際情況填寫。
    client, err := oss.New("https://oss-cn-hangzhou.aliyuncs.com", "", "", oss.SetCredentialsProvider(&provider))
    if err != nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }

    // 填寫Bucket名稱,例如examplebucket。
    bucket, err := client.Bucket("examplebucket")
    if err != nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
    
    // yourObjectName填寫Object完整路徑,完整路徑中不能包含Bucket名稱,例如exampledir/exampleobject.txt。
    // yourLocalFile填寫本地檔案的完整路徑,例如D:\\localpath\\examplefile.txt。如果未指定本地路徑,則下載後的檔案預設儲存到樣本程式所屬專案對應本地路徑中。
    // 設定分區大小為100 KB(100*1024),並指定分區下載並發數為3。
    // oss.Checkpoint(true, "")表示開啟斷點續傳下載功能。預設情況下,記錄斷點的Checkpoint檔案與下載到本地的檔案在同一目錄,名稱與本地檔案名稱相同,尾碼為.temp的檔案。您也可以使用oss.Checkpoint(true, "your-cp-file.temp")指定Checkpoint檔案。
    err = bucket.DownloadFile("file.zip", "D:\\file.zip", 100*1024, oss.Routines(3), oss.Checkpoint(true, ""))
    if err != nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
}      
#import "DownloadService.h"
#import "OSSTestMacros.h"

@implementation DownloadRequest

@end

@implementation Checkpoint

- (instancetype)copyWithZone:(NSZone *)zone {
    Checkpoint *other = [[[self class] allocWithZone:zone] init];

    other.etag = self.etag;
    other.totalExpectedLength = self.totalExpectedLength;

    return other;
}

@end


@interface DownloadService()<NSURLSessionTaskDelegate, NSURLSessionDataDelegate>

@property (nonatomic, strong) NSURLSession *session;         // 網路會話。
@property (nonatomic, strong) NSURLSessionDataTask *dataTask;   // 資料請求任務。
@property (nonatomic, copy) DownloadFailureBlock failure;    // 請求出錯。
@property (nonatomic, copy) DownloadSuccessBlock success;    // 請求成功。
@property (nonatomic, copy) DownloadProgressBlock progress;  // 下載進度。
@property (nonatomic, copy) Checkpoint *checkpoint;        // 檢查節點。
@property (nonatomic, copy) NSString *requestURLString;    // 檔案資源地址,用於下載請求。
@property (nonatomic, copy) NSString *headURLString;       // 檔案資源地址,用於head請求。
@property (nonatomic, copy) NSString *targetPath;     // 檔案儲存體路徑。
@property (nonatomic, assign) unsigned long long totalReceivedContentLength; // 已下載檔案大小。
@property (nonatomic, strong) dispatch_semaphore_t semaphore;

@end

@implementation DownloadService

- (instancetype)init
{
    self = [super init];
    if (self) {
        NSURLSessionConfiguration *conf = [NSURLSessionConfiguration defaultSessionConfiguration];
        conf.timeoutIntervalForRequest = 15;

        NSOperationQueue *processQueue = [NSOperationQueue new];
        _session = [NSURLSession sessionWithConfiguration:conf delegate:self delegateQueue:processQueue];
        _semaphore = dispatch_semaphore_create(0);
        _checkpoint = [[Checkpoint alloc] init];
    }
    return self;
}
// DownloadRequest是下載邏輯的核心。
+ (instancetype)downloadServiceWithRequest:(DownloadRequest *)request {
    DownloadService *service = [[DownloadService alloc] init];
    if (service) {
        service.failure = request.failure;
        service.success = request.success;
        service.requestURLString = request.sourceURLString;
        service.headURLString = request.headURLString;
        service.targetPath = request.downloadFilePath;
        service.progress = request.downloadProgress;
        if (request.checkpoint) {
            service.checkpoint = request.checkpoint;
        }
    }
    return service;
}

/**
 * 通過Head方法擷取檔案資訊。OSS將檔案的ETag和本地checkpoint中儲存的ETag進行對比,並返回對比結果。
 */
- (BOOL)getFileInfo {
    __block BOOL resumable = NO;
    NSURL *url = [NSURL URLWithString:self.headURLString];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:url];
    [request setHTTPMethod:@"HEAD"];
    // 處理Object相關資訊,例如ETag用於斷點續傳時進行預檢查,content-length用於計算下載進度。
    NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (error) {
            NSLog(@"擷取檔案meta資訊失敗,error : %@", error);
        } else {
            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
            NSString *etag = [httpResponse.allHeaderFields objectForKey:@"Etag"];
            if ([self.checkpoint.etag isEqualToString:etag]) {
                resumable = YES;
            } else {
                resumable = NO;
            }
        }
        dispatch_semaphore_signal(self.semaphore);
    }];
    [task resume];

    dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
    return resumable;
}

/**
 * 擷取本地檔案的大小。
 */
- (unsigned long long)fileSizeAtPath:(NSString *)filePath {
    unsigned long long fileSize = 0;
    NSFileManager *dfm = [NSFileManager defaultManager];
    if ([dfm fileExistsAtPath:filePath]) {
        NSError *error = nil;
        NSDictionary *attributes = [dfm attributesOfItemAtPath:filePath error:&error];
        if (!error && attributes) {
            fileSize = attributes.fileSize;
        } else if (error) {
            NSLog(@"error: %@", error);
        }
    }

    return fileSize;
}

- (void)resume {
    NSURL *url = [NSURL URLWithString:self.requestURLString];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:url];
    [request setHTTPMethod:@"GET"];

    BOOL resumable = [self getFileInfo];    // 如果resumable返回NO,表明不滿足斷點續傳的條件。
    if (resumable) {
        self.totalReceivedContentLength = [self fileSizeAtPath:self.targetPath];
        NSString *requestRange = [NSString stringWithFormat:@"bytes=%llu-", self.totalReceivedContentLength];
        [request setValue:requestRange forHTTPHeaderField:@"Range"];
    } else {
        self.totalReceivedContentLength = 0;
    }

    if (self.totalReceivedContentLength == 0) {
        [[NSFileManager defaultManager] createFileAtPath:self.targetPath contents:nil attributes:nil];
    }

    self.dataTask = [self.session dataTaskWithRequest:request];
    [self.dataTask resume];
}

- (void)pause {
    [self.dataTask cancel];
    self.dataTask = nil;
}

- (void)cancel {
    [self.dataTask cancel];
    self.dataTask = nil;
    [self removeFileAtPath: self.targetPath];
}

- (void)removeFileAtPath:(NSString *)filePath {
    NSError *error = nil;
    [[NSFileManager defaultManager] removeItemAtPath:self.targetPath error:&error];
    if (error) {
        NSLog(@"remove file with error : %@", error);
    }
}

#pragma mark - NSURLSessionDataDelegate

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
// 判斷下載任務是否完成,然後將結果返回給上層業務。
didCompleteWithError:(nullable NSError *)error {
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response;
    if ([httpResponse isKindOfClass:[NSHTTPURLResponse class]]) {
        if (httpResponse.statusCode == 200) {
            self.checkpoint.etag = [[httpResponse allHeaderFields] objectForKey:@"Etag"];
            self.checkpoint.totalExpectedLength = httpResponse.expectedContentLength;
        } else if (httpResponse.statusCode == 206) {
            self.checkpoint.etag = [[httpResponse allHeaderFields] objectForKey:@"Etag"];
            self.checkpoint.totalExpectedLength = self.totalReceivedContentLength + httpResponse.expectedContentLength;
        }
    }

    if (error) {
        if (self.failure) {
            NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:error.userInfo];
            [userInfo oss_setObject:self.checkpoint forKey:@"checkpoint"];

            NSError *tError = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
            self.failure(tError);
        }
    } else if (self.success) {
        self.success(@{@"status": @"success"});
    }
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)dataTask.response;
    if ([httpResponse isKindOfClass:[NSHTTPURLResponse class]]) {
        if (httpResponse.statusCode == 200) {
            self.checkpoint.totalExpectedLength = httpResponse.expectedContentLength;
        } else if (httpResponse.statusCode == 206) {
            self.checkpoint.totalExpectedLength = self.totalReceivedContentLength +  httpResponse.expectedContentLength;
        }
    }

    completionHandler(NSURLSessionResponseAllow);
}
// 將接收到的網路資料以追加上傳的方式寫入到檔案中,並更新下載進度。
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {

    NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:self.targetPath];
    [fileHandle seekToEndOfFile];
    [fileHandle writeData:data];
    [fileHandle closeFile];

    self.totalReceivedContentLength += data.length;
    if (self.progress) {
        self.progress(data.length, self.totalReceivedContentLength, self.checkpoint.totalExpectedLength);
    }
}

@end
#include <alibabacloud/oss/OssClient.h>
using namespace AlibabaCloud::OSS;

int main(void)
{
    /* 初始化OSS帳號資訊 */
            
    /* 填寫Bucket所在地區對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。*/
    std::string Endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
    /* 填寫Bucket名稱,例如examplebucket。*/
    std::string BucketName = "examplebucket";
    /* 填寫Object完整路徑,完整路徑中不能包含Bucket名稱,例如exampledir/exampleobject.txt。*/
    std::string ObjectName = "exampledir/exampleobject.txt";
    /* 下載Object到本地檔案examplefile.txt,並儲存到指定的本地路徑中(D:\\localpath)。如果指定的本地檔案存在會覆蓋,不存在則建立。*/
    /* 如果未指定本地路徑,則下載後的檔案預設儲存到樣本程式所屬專案對應本地路徑中。*/
    std::string DownloadFilePath = "D:\\localpath\\examplefile.txt";
    /* 設定斷點記錄檔案所在的目錄,並確保指定的目錄已存在,例如D:\\localpath。*/
    /* 只有當Object下載中斷產生了斷點記錄檔案後,如果需要繼續下載該Object,才需要設定對應的斷點記錄檔案。下載完成後,該檔案會被刪除。*/
    std::string CheckpointFilePath = "D:\\localpath";

    /* 初始化網路等資源。*/
    InitializeSdk();

    ClientConfiguration conf;
    /* 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/
    auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>();
    OssClient client(Endpoint, credentialsProvider, conf);

    /* 斷點續傳下載。*/
    DownloadObjectRequest request(BucketName, ObjectName, DownloadFilePath, CheckpointFilePath);
    auto outcome = client.ResumableDownloadObject(request);

    if (!outcome.isSuccess()) {
        /* 異常處理。*/
        std::cout << "ResumableDownloadObject fail" <<
        ",code:" << outcome.error().Code() <<
        ",message:" << outcome.error().Message() <<
        ",requestId:" << outcome.error().RequestId() << std::endl;
        return -1;
    }

    /* 釋放網路等資源。*/
    ShutdownSdk();
    return 0;
}
#include "oss_api.h"
#include "aos_http_io.h"
/* yourEndpoint填寫Bucket所在地區對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。*/
const char *endpoint = "yourEndpoint";

/* 填寫Bucket名稱,例如examplebucket。*/
const char *bucket_name = "examplebucket";
/* 填寫Object完整路徑,完整路徑中不能包含Bucket名稱,例如exampledir/exampleobject.txt。*/
const char *object_name = "exampledir/exampleobject.txt";
/* 填寫本地檔案的完整路徑。*/
const char *local_filename = "yourLocalFilename";
void init_options(oss_request_options_t *options)
{
    options->config = oss_config_create(options->pool);
    /* 用char*類型的字串初始化aos_string_t類型。*/
    aos_str_set(&options->config->endpoint, endpoint);
    /* 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/    
    aos_str_set(&options->config->access_key_id, getenv("OSS_ACCESS_KEY_ID"));
    aos_str_set(&options->config->access_key_secret, getenv("OSS_ACCESS_KEY_SECRET"));
    /* 是否使用了CNAME。0表示不使用。*/
    options->config->is_cname = 0;
    /* 用於設定網路相關參數,比如逾時時間等。*/
    options->ctl = aos_http_controller_create(options->pool, 0);
}
int main(int argc, char *argv[])
{
    /* 在程式入口調用aos_http_io_initialize方法來初始化網路、記憶體等全域資源。*/
    if (aos_http_io_initialize(NULL, 0) != AOSE_OK) {
        exit(1);
    }
    /* 用於記憶體管理的記憶體池(pool),等價於apr_pool_t。其實現代碼在apr庫中。*/
    aos_pool_t *pool;
    /* 重新建立一個記憶體池,第二個參數是NULL,表示沒有繼承其它記憶體池。*/
    aos_pool_create(&pool, NULL);
    /* 建立並初始化options,該參數包括endpoint、access_key_id、acces_key_secret、is_cname、curl等全域配置資訊。*/
    oss_request_options_t *oss_client_options;
    /* 在記憶體池中分配記憶體給options。*/
    oss_client_options = oss_request_options_create(pool);
    /* 初始化Client的選項oss_client_options。*/
    init_options(oss_client_options);
    /* 初始化參數。*/
    aos_string_t bucket;
    aos_string_t object;
    aos_string_t file;
    aos_table_t *headers = NULL;
    aos_table_t *resp_headers = NULL; 
    aos_status_t *resp_status = NULL; 
    oss_resumable_clt_params_t *clt_params;
    aos_str_set(&bucket, bucket_name);
    aos_str_set(&object, object_name);
    aos_str_set(&file, local_filename);
    /* 斷點續傳檔案。*/
    clt_params = oss_create_resumable_clt_params_content(pool, 1024 * 100, 3, AOS_TRUE, NULL);
    resp_status = oss_resumable_download_file(oss_client_options, &bucket, &object, &file, headers, NULL, clt_params, NULL, &resp_headers);
    if (aos_status_is_ok(resp_status)) {
        printf("download succeeded\n");
    } else {
        printf("download failed\n");
    }
    /* 釋放記憶體池,相當於釋放了請求過程中各資源分派的記憶體。*/
    aos_pool_destroy(pool);
    /* 釋放之前分配的全域資源。*/
    aos_http_io_deinitialize();
    return 0;
}
require 'aliyun/oss'

client = Aliyun::OSS::Client.new(
  # Endpoint以華東1(杭州)為例,其它Region請按實際情況填寫。
  endpoint: 'https://oss-cn-hangzhou.aliyuncs.com',
  # 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
  access_key_id: ENV['OSS_ACCESS_KEY_ID'],
  access_key_secret: ENV['OSS_ACCESS_KEY_SECRET']
)

# 填寫Bucket名稱,例如examplebucket。
bucket = client.get_bucket('examplebucket')
# key填寫Object完整路徑,Object完整路徑中不能包含Bucket名稱,例如exampledir/example.zip。
# file填寫本地檔案的完整路徑,例如/tmp/example.zip。
bucket.resumable_download('exampledir/example.zip', '/tmp/example.zip') do |p|
  puts "Progress: #{p}"
end

bucket.resumable_download(
  'exampledir/example.zip', '/tmp/example.zip',
  # cpt_file填寫用於記錄斷點資訊的檔案路徑。
  :part_size => 100 * 1024, :cpt_file => '/tmp/example.zip.cpt') { |p|
  puts "Progress: #{p}"
}

更多參考

  • 如何在開啟了版本控制的Bucket中下載檔案,請參見開啟版本控制下Object的操作

  • 如果您希望將私人Bucket的Object提供給第三方進行下載,請通過STS臨時訪問憑證或簽名URL的方式授權第三方下載檔案。具體操作,請參見授權給第三方下載