すべてのプロダクト
Search
ドキュメントセンター

Object Storage Service:レジューム可能なダウンロード

最終更新日:Jun 18, 2025

Object Storage Service (OSS) からローカルコンピュータに 5 GB を超える大きなオブジェクトをダウンロードすると、ネットワークの中断やプログラムのクラッシュが原因で、オブジェクトのダウンロードに失敗することがあります。複数回再試行してもオブジェクトのダウンロードに失敗する場合は、レジューム可能なダウンロードを使用できます。オブジェクトを複数のパートに分割し、パートを並行してダウンロードすることで、ダウンロードを高速化できます。レジューム可能なダウンロード中、ダウンロードの進捗状況はチェックポイントファイルに記録されます。パートのダウンロードに失敗した場合、次のダウンロードはチェックポイントファイルに記録されている位置から開始されます。すべてのパートがダウンロードされると、すべてのパートが完全なオブジェクトに結合されます。

前提条件

  • アーカイブオブジェクトのダウンロード: アーカイブオブジェクトが復元されているか、アーカイブオブジェクトを保存するバケットでアーカイブオブジェクトのリアルタイムアクセスが有効になっています。詳細については、「オブジェクトの復元」および「アーカイブオブジェクトのリアルタイムアクセス」をご参照ください。

  • コールドアーカイブまたはディープコールドアーカイブオブジェクトのダウンロード: コールドアーカイブまたはディープコールドアーカイブオブジェクトが復元されています。詳細については、「オブジェクトの復元」をご参照ください。

使用上の注意

レジューム可能なダウンロードは、OSS SDK を使用することによってのみ実行できます。レジューム可能なダウンロードを実行する場合は、次の点に注意してください。

  • このトピックでは、中国 (杭州) リージョンのパブリックエンドポイントが使用されています。OSS と同じリージョン内の他の Alibaba Cloud サービスから OSS にアクセスする場合は、内部エンドポイントを使用します。OSS のリージョンとエンドポイントの詳細については、「リージョンとエンドポイント」をご参照ください。

  • このトピックでは、アクセス認証情報は環境変数から取得されます。アクセス認証情報を構成する方法の詳細については、「アクセス認証情報の構成」をご参照ください。

  • このトピックでは、OSS エンドポイントを使用して OSSClient インスタンスが作成されます。カスタムドメイン名または Security Token Service (STS) を使用して OSSClient インスタンスを作成する場合は、「OSSClient インスタンスの構成」をご参照ください。

  • レジューム可能なダウンロードを使用するには、oss:GetObject 権限が必要です。詳細については、「RAM ユーザーへのカスタムポリシーのアタッチ」をご参照ください。

  • OSS SDK は、チェックポイントファイルにダウンロードの進捗状況を記録します。チェックポイントファイルへの書き込み権限があることを確認してください。

  • チェックポイントファイルに含まれるチェックサムを変更することはできません。チェックポイントファイルが破損している場合は、すべてのパートを再度ダウンロードする必要があります。

  • オブジェクトの ETag が一致しない場合、またはダウンロード中にパートが失われたり変更されたりした場合は、オブジェクトを再度ダウンロードする必要があります。

OSS SDK の使用

次のサンプルコードは、一般的なプログラミング言語の OSS SDK を使用してレジューム可能なダウンロードを実行する方法の例を示しています。他のプログラミング言語の OSS SDK を使用してレジューム可能なダウンロードを実行する方法の詳細については、「概要」をご参照ください。

import com.aliyun.oss.ClientBuilderConfiguration;
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.common.comm.SignVersion;
import com.aliyun.oss.model.*;

public class Demo {
    public static void main(String[] args) throws Exception {
        // この例では、中国 (杭州) リージョンのエンドポイントが使用されています。実際のエンドポイントを指定してください。
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が構成されていることを確認してください。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // バケットの名前を指定します。例: examplebucket。
        String bucketName = "examplebucket";
        // オブジェクトの完全なパスを指定します。例: exampledir/exampleobject.txt。完全なパスにバケット名を含めないでください。
        String objectName = "exampledir/exampleobject.txt";
        // バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、リージョンを cn-hangzhou に設定します。
        String region = "cn-hangzhou";

        // OSSClient インスタンスを作成します。
        // OSSClient が不要になったら、shutdown メソッドを呼び出して関連付けられているリソースを解放します。
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);        
        OSS ossClient = OSSClientBuilder.create()
        .endpoint(endpoint)
        .credentialsProvider(credentialsProvider)
        .clientConfiguration(clientBuilderConfiguration)
        .region(region)               
        .build();
        
      	try {
            // 10 個のパートを同時にダウンロードできるレジューム可能なダウンロードを実行します。
            DownloadFileRequest downloadFileRequest = new DownloadFileRequest(bucketName, objectName);
            // オブジェクトをダウンロードする完全なパスを指定します。例: 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。
            // チェックポイントファイルは、ダウンロードが中断されたときに生成されます。ダウンロードタスクを再開する場合は、チェックポイントファイルの完全なパスを指定する必要があります。オブジェクトがダウンロードされると、チェックポイントファイルは削除されます。
            //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();
            }
        }
    }
}
import argparse
import alibabacloud_oss_v2 as oss

# コマンドライン引数を解析するためのパーサーを作成し、スクリプトの目的を記述します。
parser = argparse.ArgumentParser(description="download file sample")

# --region パラメーターを指定して、バケットが配置されているリージョンを示します。このパラメーターは必須です。
parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
# --bucket パラメーターを指定して、オブジェクトが保存されているバケットの名前を示します。このパラメーターは必須です。
parser.add_argument('--bucket', help='The name of the bucket.', required=True)
# --endpoint パラメーターを指定して、バケットが配置されているリージョンのエンドポイントを示します。このパラメーターはオプションです。
parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
# --key パラメーターを指定して、オブジェクトの名前を示します。このパラメーターは必須です。
parser.add_argument('--key', help='The name of the object.', required=True)
# --file_path パラメーターを指定して、オブジェクトのダウンロード先パスを示します。このパラメーターは必須です。例: "/Users/yourLocalPath/yourFileName"
parser.add_argument('--file_path', help='The path to save the downloaded file.', required=True)

def main():
    # コマンドライン引数を解析して、指定された値を取得します。
    args = parser.parse_args()

    # OSS にアクセスするために必要な認証情報を環境変数からロードします。
    credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()

    # デフォルト構成を使用して構成オブジェクトを作成し、認証プロバイダーを指定します。
    cfg = oss.config.load_default()
    cfg.credentials_provider = credentials_provider
    
    # ユーザーが提供したコマンドラインパラメーターに基づいて、構成オブジェクトの region 属性を指定します。
    cfg.region = args.region

    # カスタムエンドポイントが提供されている場合は、cfg オブジェクトの endpoint 属性を、提供されたエンドポイントで更新します。
    if args.endpoint is not None:
        cfg.endpoint = args.endpoint

    # 前述の構成を使用して OSSClient インスタンスを初期化し、インスタンスが OSS と対話できるようにします。
    client = oss.Client(cfg)

    # ダウンローダーを作成し、詳細オプションを指定します。
    downloader = client.downloader(
        use_temp_file=True,            # 一時ファイルの使用を有効にします。
        enable_checkpoint=True,        # レジューム可能なダウンロードを有効にします。
        checkpoint_dir=args.file_path, # チェックポイントファイルの保存ディレクトリを指定します。
        verify_data=True # データ検証を指定します。
    )

    # メソッドを呼び出してオブジェクトをダウンロードします。
    result = downloader.download_file(
        oss.GetObjectRequest(
            bucket=args.bucket,  # バケット名を指定します。
            key=args.key,        # ダウンロードするオブジェクトの名前を指定します。
        ),
        filepath=args.file_path  # オブジェクトのダウンロード先ローカルファイルパスを指定します。
    )

    # 書き込まれたバイト数を含む結果を表示します。
    print(f'written: {result.written}')

# スクリプトが直接実行されたときに main 関数を呼び出して、処理ロジックを開始します。
if __name__ == "__main__":
    main()  # スクリプトのエントリポイント。プログラムフローはここから開始されます。
package main

import (
	"context"
	"flag"
	"log"

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)

// グローバル変数を定義します。
var (
	region     string // バケットが配置されているリージョン。
	bucketName string // バケットの名前。
	objectName string // オブジェクトの名前。
)

// init 関数を使用してパラメーターを初期化します。
func init() {
	flag.StringVar(&region, "region", "", "バケットが配置されているリージョン。")
	flag.StringVar(&bucketName, "bucket", "", "バケットの名前。")
	flag.StringVar(&objectName, "src-object", "", "ソースオブジェクトの名前。")
}

func main() {
	// パラメーターを解析します。
	flag.Parse()

	// バケット名が空かどうかを確認します。
	if len(bucketName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("無効なパラメーター、バケット名が必要です")
	}

	// リージョンが空かどうかを確認します。
	if len(region) == 0 {
		flag.PrintDefaults()
		log.Fatalf("無効なパラメーター、リージョンが必要です")
	}

	// ソースオブジェクト名が空かどうかを確認します。
	if len(objectName) == 0 {
		flag.PrintDefaults()
		log.Fatalf("無効なパラメーター、ソースオブジェクト名が必要です")
	}

	// OSS クライアント構成を作成します。
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion(region)

	// OSS クライアントを作成します。
	client := oss.NewClient(cfg)

	// ダウンローダーを作成します。
	d := client.NewDownloader()

	// オブジェクトをダウンロードするリクエストを作成します。
	request := &oss.GetObjectRequest{
		Bucket: oss.Ptr(bucketName), // バケットの名前。
		Key:    oss.Ptr(objectName), // オブジェクトの名前。
	}

	// ローカルファイルのパス。
	localFile := "local-file"

	// ダウンローダーオプションを指定します。
	downloaderOptions := func(do *oss.DownloaderOptions) {
		do.EnableCheckpoint = true        // チェックポイントの記録を有効にします。
		do.CheckpointDir = "./checkpoint" // チェックポイントファイルのパスを指定します。
		do.UseTempFile = true             // 一時ファイルの使用を指定します。
	}

	// リクエストを実行してオブジェクトをダウンロードします。
	result, err := d.DownloadFile(context.TODO(), request, localFile, downloaderOptions)
	if err != nil {
		log.Fatalf("ファイルのダウンロードに失敗しました %v", err)
	}

	// 成功レスポンスを出力します。
	log.Printf("ファイル %s を local-file に正常にダウンロードしました。サイズ: %d", objectName, result.Written)
}
using Aliyun.OSS;
using Aliyun.OSS.Common;

// バケットが配置されているリージョンのエンドポイントを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、エンドポイントを 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");
// バケットの名前を指定します。例: examplebucket。
var bucketName = "examplebucket";
// オブジェクトの完全なパスを指定します。完全なパスにバケット名を含めないでください。例: exampledir/exampleobject.txt。
var objectName = "exampleobject.txt";
// オブジェクトを D:\\localpath にダウンロードします。オブジェクトがダウンロードされると、ローカルファイルの名前は examplefile.txt になります。同じ名前のファイルが既に存在する場合は、ダウンロードされたオブジェクトによってファイルが上書きされます。そうでない場合は、ダウンロードされたオブジェクトがパスに保存されます。
// ダウンロードされたオブジェクトのパスを指定しない場合、ダウンロードされたオブジェクトは、サンプルプログラムが属するプロジェクトのパスに保存されます。
var downloadFilename = "D:\\localpath\\examplefile.txt";
// チェックポイントファイルの完全なパスを指定します。例: D:\\localpath\\examplefile.txt.dcp。
// チェックポイントファイルは、ダウンロードが中断されたときに生成されます。ダウンロードタスクを再開する場合は、チェックポイントファイルの完全なパスを指定する必要があります。オブジェクトがダウンロードされると、チェックポイントファイルは削除されます。
var checkpointDir = "D:\\localpath\\examplefile.txt.dcp";
// バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、リージョンを cn-hangzhou に設定します。
const string region = "cn-hangzhou";

// ClientConfiguration インスタンスを作成し、要件に基づいてデフォルトパラメーターを変更します。
var conf = new ClientConfiguration();

// 署名アルゴリズム V4 を使用します。
conf.SignatureVersion = SignatureVersion.V4;

// OSSClient インスタンスを作成します。
var client = new OssClient(endpoint, accessKeyId, accessKeySecret, conf);
client.SetRegion(region);
try
{
    // DownloadObjectRequest を使用して複数のパラメーターを構成します。
    DownloadObjectRequest request = new DownloadObjectRequest(bucketName, objectName, downloadFilename)
    {
        // ダウンロードする各パートのサイズを指定します。単位: バイト。
        PartSize = 8 * 1024 * 1024,
        // 同時スレッド数を指定します。
        ParallelThreadCount = 3,
        // checkpointDir は、レジューム可能なダウンロードの進捗状況に関する情報を保存するために使用されるファイルです。パートのダウンロードに失敗した場合、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);
}
#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;    // ダウンロードリクエストで使用されるオブジェクトリソース URL。
@property (nonatomic, copy) NSString *headURLString;       // HEAD リクエストで使用されるオブジェクトリソース URL。
@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 をローカルチェックポイントファイルに保存されている ETag と比較し、比較結果を返します。
 */
- (BOOL)getFileInfo {
    __block BOOL resumable = NO;
    NSURL *url = [NSURL URLWithString:self.headURLString];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:url];
    [request setHTTPMethod:@"HEAD"];
    // オブジェクトに関する情報を処理します。たとえば、ETag はレジューム可能なアップロード中の事前チェックに使用され、Content-Length ヘッダーはダウンロードの進捗状況の計算に使用されます。
    NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (error) {
            NSLog(@"オブジェクトメタデータの取得に失敗しました。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);
}
// 受信したネットワークデータを append アップロードを使用してオブジェクトに書き込み、ダウンロードの進捗状況を更新します。
- (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 にアクセスするために使用されるアカウントに関する情報を初期化します。 */
            
    /* バケットが配置されているリージョンのエンドポイントを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。 */
    std::string Endpoint = "yourEndpoint";
    /* バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、リージョンを cn-hangzhou に設定します。 */
    std::string Region = "yourRegion";
    /* バケットの名前を指定します。例: examplebucket。 */
    std::string BucketName = "examplebucket";
    /* オブジェクトの完全なパスを指定します。完全なパスにバケット名を含めないでください。例: exampledir/exampleobject.txt。 */
    std::string ObjectName = "exampledir/exampleobject.txt";
    /* オブジェクトをローカルパス D:\\localpath に examplefile.txt という名前のローカルファイルとしてダウンロードします。指定されたパスに同じ名前のファイルが既に存在する場合は、ダウンロードされたオブジェクトによってファイルが上書きされます。そうでない場合は、ダウンロードされたオブジェクトがパスに保存されます。 */
    /* ローカルファイルのパスを指定しない場合、ダウンロードされたオブジェクトは、サンプルプログラムが属するプロジェクトのパスに保存されます。 */
    std::string DownloadFilePath = "D:\\localpath\\examplefile.txt";
    /* チェックポイントファイルが保存されるディレクトリを指定し、指定されたディレクトリが存在することを確認します (例: D:\\localpath)。 */
    /* チェックポイントファイルは、ダウンロードが中断されたときに生成されます。ダウンロードタスクを再開する場合は、チェックポイントファイルの完全なパスを指定する必要があります。オブジェクトがダウンロードされると、チェックポイントファイルは削除されます。 */
    std::string CheckpointFilePath = "D:\\localpath";

    /* ネットワークリソースなどのリソースを初期化します。 */
    InitializeSdk();

    ClientConfiguration conf;
    conf.signatureVersion = SignatureVersionType::V4;
    /* 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、OSS_ACCESS_KEY_ID および OSS_ACCESS_KEY_SECRET 環境変数が構成されていることを確認してください。 */
    auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>();
    OssClient client(Endpoint, credentialsProvider, conf);
    client.SetRegion(Region);

    /* レジューム可能なダウンロードを開始します。 */
    DownloadObjectRequest request(BucketName, ObjectName, DownloadFilePath, CheckpointFilePath);
    auto outcome = client.ResumableDownloadObject(request);

    if (!outcome.isSuccess()) {
        /* 例外を処理します。 */
        std::cout << "ResumableDownloadObject failed, " << outcome.error() << std::endl;
        return 0;
    }
    /* ダウンロードされたオブジェクトのメタデータを取得します。 */
    std::cout << "ResumableDownloadObject success, " << outcome.result().Metadata().ETag() << std::endl;

    /* ネットワークリソースなどのリソースを解放します。 */
    ShutdownSdk();

    return 0;
}
#include "oss_api.h"
#include "aos_http_io.h"
/* バケットが配置されているリージョンのエンドポイントを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。 */
const char *endpoint = "yourEndpoint";

/* バケットの名前を指定します。例: examplebucket。 */
const char *bucket_name = "examplebucket";
/* オブジェクトの完全なパスを指定します。完全なパスにバケット名を含めないでください。例: exampledir/exampleobject.txt。 */
const char *object_name = "exampledir/exampleobject.txt";
/* ローカルファイルの完全なパスを指定します。 */
const char *local_filename = "yourLocalFilename";
/* バケットが配置されているリージョンを指定します。たとえば、バケットが中国 (杭州) リージョンにある場合は、リージョンを cn-hangzhou に設定します。 */
const char *region = "yourRegion";
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"));
    // 2 つの追加パラメーターを指定します。
    aos_str_set(&options->config->region, region);
    options->config->signature_version = 4;
    /* CNAME を使用するかどうかを指定します。値 0 は、CNAME が使用されていないことを示します。 */
    options->config->is_cname = 0;
    /* タイムアウト期間などのネットワークパラメーターを指定します。 */
    options->ctl = aos_http_controller_create(options->pool, 0);
}
int main(int argc, char *argv[])
{
    /* main() で aos_http_io_initialize メソッドを呼び出して、ネットワークやメモリリソースなどのグローバルリソースを初期化します。 */
    if (aos_http_io_initialize(NULL, 0) != AOSE_OK) {
        exit(1);
    }
    /* メモリを管理するためのメモリプールを作成します。 aos_pool_t は apr_pool_t と同等です。メモリプールを作成するために使用されるコードは、APR ライブラリに含まれています。 */
    aos_pool_t *pool;
    /* メモリプールを作成します。2 番目のパラメーターの値は NULL です。この値は、プールが他のメモリプールを継承しないことを指定します。 */
    aos_pool_create(&pool, NULL);
    /* オプションを作成して初期化します。このパラメーターには、エンドポイント、access_key_id、access_key_secret、is_cname、curl などのグローバル構成情報が含まれます。 */
    oss_request_options_t *oss_client_options;
    /* メモリプール内のメモリリソースをオプションに割り当てます。 */
    oss_client_options = oss_request_options_create(pool);
    /* 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: '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']
)

# バケットの名前を指定します。例: examplebucket。
bucket = client.get_bucket('examplebucket')
# key をオブジェクトの完全なパスに設定します。完全なパスにバケット名を含めないでください。例: 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}"
}

参考資料