Amazon S3 Glacier で AWS SDK for .NET を使用してアーカイブをダウンロードする - Amazon S3 Glacier

このページは、Vaults と 2012 RESTAPI年のオリジナルを使用する S3 Glacier サービスの既存のお客様専用です。

アーカイブストレージソリューションをお探しの場合は、Amazon S3、S3 Glacier Instant Retrieval、S3 Glacier Flexible Retrieval、S3 GlacierS3 Deep Archive の S3 Glacier ストレージクラスを使用することをお勧めします。これらのストレージオプションの詳細については、Amazon S3 ユーザーガイドの「S3 Glacier ストレージクラス」およびS3 Glacier ストレージクラスを使用した長期データストレージ」を参照してください。 Amazon S3 これらのストレージクラスは Amazon S3 を使用しAPI、すべてのリージョンで利用可能で、Amazon S3 コンソール内で管理できます。Storage Cost Analysis、Storage Lens、高度なオプションの暗号化機能などの機能を提供します。

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

Amazon S3 Glacier で AWS SDK for .NET を使用してアーカイブをダウンロードする

両方高レベル API と低レベル API.NET 用の Amazon SDK で提供されており、アーカイブをダウンロードする方法を提供します。

AWS SDK for .NET の高レベル API を使用してアーカイブをダウンロードする

高レベル API の ArchiveTransferManager クラスには、アーカイブのダウンロードに使用できる Download メソッドが用意されています。

重要

-ArchiveTransferManagerクラスは、Amazon Simple Notification Service (Amazon SNS) トピックと、そのトピックにサブスクライブされている Amazon Simple Queue Service (Amazon SQS) キューを作成します。その後、アーカイブの取り出しジョブを開始し、使用可能にするアーカイブを探してキューをポーリングします。アーカイブが使用可能になると、ダウンロードが開始されます。取得時間に関する詳細については、「アーカイブの取り出しオプション」を参照してください。

例: AWS SDK for .NET の高レベル API を使用してアーカイブをダウンロードする

次の C# コード例では、米国西部(オレゴン リージョン (examplevault) のボールト からアーカイブをダウンロードします。

この例を実行するための詳しい手順については、「コード例の実行」を参照してください。ここに示したコードは、既存のアーカイブ ID とダウンロードしたアーカイブを保存するローカルファイルパスで更新する必要があります。

using System; using Amazon.Glacier; using Amazon.Glacier.Transfer; using Amazon.Runtime; namespace glacier.amazon.com.docsamples { class ArchiveDownloadHighLevel { static string vaultName = "examplevault"; static string archiveId = "*** Provide archive ID ***"; static string downloadFilePath = "*** Provide the file name and path to where to store the download ***"; public static void Main(string[] args) { try { var manager = new ArchiveTransferManager(Amazon.RegionEndpoint.USWest2); var options = new DownloadOptions(); options.StreamTransferProgress += ArchiveDownloadHighLevel.progress; // Download an archive. Console.WriteLine("Intiating the archive retrieval job and then polling SQS queue for the archive to be available."); Console.WriteLine("Once the archive is available, downloading will begin."); manager.Download(vaultName, archiveId, downloadFilePath, options); Console.WriteLine("To continue, press Enter"); Console.ReadKey(); } catch (AmazonGlacierException e) { Console.WriteLine(e.Message); } catch (AmazonServiceException e) { Console.WriteLine(e.Message); } catch (Exception e) { Console.WriteLine(e.Message); } Console.WriteLine("To continue, press Enter"); Console.ReadKey(); } static int currentPercentage = -1; static void progress(object sender, StreamTransferProgressArgs args) { if (args.PercentDone != currentPercentage) { currentPercentage = args.PercentDone; Console.WriteLine("Downloaded {0}%", args.PercentDone); } } } }

AWS SDK for .NET の低レベル API を使用してアーカイブをダウンロードする

以下に、AWS SDK for .NET の低レベル API を使用して、Amazon S3 Glacier (S3 Glacier) アーカイブをダウンロードするためのステップを示します。

  1. AmazonGlacierClient クラスのインスタンス(クライアント)を作成します。

    アーカイブのダウンロード元となる AWS リージョンを指定する必要があります。このクライアントを使用して実行するすべてのオペレーションは、そのAWSリージョンに適用されます。

  2. archive-retrieval メソッドを実行して、InitiateJob ジョブを開始します。

    InitiateJobRequest クラスのインスタンスを作成することにより、ダウンロードするアーカイブのアーカイブ ID や、 S3 Glacier がジョブの完了メッセージを投稿する Amazon SNS トピック (オプション) などのジョブ情報を入力します。 は、レスポンスとしてジョブ ID を返します。S3 Glacier は、レスポンスとしてジョブ ID を返します。レスポンスは、InitiateJobResponse クラスのインスタンスで使用できます。

    AmazonGlacierClient client; client = new AmazonGlacierClient(Amazon.RegionEndpoint.USWest2); InitiateJobRequest initJobRequest = new InitiateJobRequest() { VaultName = vaultName, JobParameters = new JobParameters() { Type = "archive-retrieval", ArchiveId = "*** Provide archive id ***", SNSTopic = "*** Provide Amazon SNS topic ARN ***", } }; InitiateJobResponse initJobResponse = client.InitiateJob(initJobRequest); string jobId = initJobResponse.JobId;

    必要に応じて、以下のリクエストに示すように、バイト範囲を指定して、アーカイブの一部のみを準備するよう S3 Glacier にリクエストすることもできます。リクエストでは S3 Glacier に対し、アーカイブの 1 MB から 2 MB までの部分のみを準備するように指定しています。

    AmazonGlacierClient client; client = new AmazonGlacierClient(Amazon.RegionEndpoint.USWest2); InitiateJobRequest initJobRequest = new InitiateJobRequest() { VaultName = vaultName, JobParameters = new JobParameters() { Type = "archive-retrieval", ArchiveId = "*** Provide archive id ***", SNSTopic = "*** Provide Amazon SNS topic ARN ***", } }; // Specify byte range. int ONE_MEG = 1048576; initJobRequest.JobParameters.RetrievalByteRange = string.Format("{0}-{1}", ONE_MEG, 2 * ONE_MEG -1); InitiateJobResponse initJobResponse = client.InitiateJob(initJobRequest); string jobId = initJobResponse.JobId;
  3. ジョブが完了するまで待ちます。

    ジョブの出力をダウンロードする準備が整うまで待つ必要があります。ボールトの通知設定により Amazon Simple Notification Service (Amazon SNS) トピックを指定している場合、またはジョブを開始したときに Amazon SNS トピックを指定している場合は、ジョブの完了後に S3 Glacier によりそのトピックにメッセージが送信されます。以下のセクションに示しているコード例では、Amazon SNS を使用して、 S3 Glacier でメッセージを発行します。

    また、DescribeJob メソッドを呼び出して S3 Glacier にポーリングすることで、ジョブの完了ステータスを調べることもできます。ただし、通知のために Amazon SNS トピックを使用することをお勧めします。

  4. GetJobOutput メソッドを実行して、ジョブの出力 (アーカイブデータ) をダウンロードします。

    GetJobOutputRequest クラスのインスタンスを作成することにより、ジョブ ID やボールト名などのリクエスト情報を指定します。S3 Glacier により返される出力は GetJobOutputResponse オブジェクトで使用できます。

    GetJobOutputRequest getJobOutputRequest = new GetJobOutputRequest() { JobId = jobId, VaultName = vaultName }; GetJobOutputResponse getJobOutputResponse = client.GetJobOutput(getJobOutputRequest); using (Stream webStream = getJobOutputResponse.Body) { using (Stream fileToSave = File.OpenWrite(fileName)) { CopyStream(webStream, fileToSave); } }

    前述のコードスニペットは、ジョブの出力全体をダウンロードします。このほか、GetJobOutputRequest でバイト範囲を指定することにより、出力の一部のみを取得したり、出力全体を小さなチャンクに分けてダウンロードしたりできます。

    GetJobOutputRequest getJobOutputRequest = new GetJobOutputRequest() { JobId = jobId, VaultName = vaultName }; getJobOutputRequest.SetRange(0, 1048575); // Download only the first 1 MB chunk of the output.

    GetJobOutput 呼び出しに対するレスポンスとして、 S3 Glacier では、特定の条件が満たされた場合に、ダウンロードしたデータの一部のチェックサムを返します。詳細については、「データをダウンロードするときのチェックサムの受信」を参照してください。

    ダウンロードにエラーがないことを確認するために、クライアント側でチェックサムを計算し、S3 Glacier からレスポンスとして送信されたチェックサムと比較できます。

    オプションの範囲が指定されたアーカイブの取得ジョブの場合は、ジョブの説明を取得したときに取得する範囲のチェックサムが含まれます(SHA256TreeHash)。この値によって、後でダウンロードするバイト範囲全体の正確性を詳しく確認できます。たとえば、木構造ハッシュ可能なアーカイブ範囲を取得するジョブを開始してから、出力を複数のチャンクに分けてダウンロードし、GetJobOutput リクエストでそれぞれチェックサムが返されるようにした場合は、クライアント側でダウンロードした各部分のチェックサムを計算してから木構造ハッシュを計算することができます。この計算結果を、S3 Glacier でジョブの説明リクエストに対して返されたレスポンスのチェックサムと比較して、ダウンロードしたバイト範囲全体が S3 Glacier に格納されているバイト範囲と同じであることを確認できます。

    実例については、「例 2: AWS SDK for .NET の低レベル API を使用したアーカイブの取得 チャンクに分けた出力のダウンロード」を参照してください。

例 1: AWS SDK for .NET の低レベル API を使用したアーカイブの取得

次の C# コード例は、指定したボールトからアーカイブをダウンロードします。この例では、ジョブが完了した後で、単一の GetJobOutput 呼び出しで出力全体をダウンロードします。出力をチャンクに分けてダウンロードする例については、「例 2: AWS SDK for .NET の低レベル API を使用したアーカイブの取得 チャンクに分けた出力のダウンロード」を参照してください。

この例では次のタスクを実行しています。

  • Amazon Simple Notification Service (Amazon SNS) のトピックを設定する

    S3 Glacier は、ジョブの完了後、このトピックに通知を送信します。

  • Amazon Simple Queue Service (Amazon SQS) キューを設定する

    この例では、ポリシーをキューにアタッチして、Amazon SNS トピックでメッセージを投稿できるようにします。

  • 指定したアーカイブをダウンロードするジョブを開始します。

    この例では、ジョブのリクエストとして、S3 Glacier によりジョブの完了後にメッセージが送信されるように Amazon SNS トピックを指定します。

  • Amazon SQS キューにメッセージがあるかどうかを定期的に確認します。

    メッセージがある場合は、JSON を解析し、ジョブが正常に完了したかどうかを確認します。正常に完了している場合は、アーカイブをダウンロードします。コード例では、JSON.NET ライブラリ (JSON.NET 参照) を使用して JSON を解析しています。

  • Amazon SNS トピックおよび作成された Amazon SQS キューを削除して、クリーンアップします。

using System; using System.Collections.Generic; using System.IO; using System.Threading; using Amazon.Glacier; using Amazon.Glacier.Model; using Amazon.Runtime; using Amazon.SimpleNotificationService; using Amazon.SimpleNotificationService.Model; using Amazon.SQS; using Amazon.SQS.Model; using Newtonsoft.Json; namespace glacier.amazon.com.docsamples { class ArchiveDownloadLowLevelUsingSNSSQS { static string topicArn; static string queueUrl; static string queueArn; static string vaultName = "*** Provide vault name ***"; static string archiveID = "*** Provide archive ID ***"; static string fileName = "*** Provide the file name and path to where to store downloaded archive ***"; static AmazonSimpleNotificationServiceClient snsClient; static AmazonSQSClient sqsClient; const string SQS_POLICY = "{" + " \"Version\" : \"2012-10-17\"," + " \"Statement\" : [" + " {" + " \"Sid\" : \"sns-rule\"," + " \"Effect\" : \"Allow\"," + " \"Principal\" : {\"Service\" : \"sns.amazonaws.com\" }," + " \"Action\" : \"sqs:SendMessage\"," + " \"Resource\" : \"{QueueArn}\"," + " \"Condition\" : {" + " \"ArnLike\" : {" + " \"aws:SourceArn\" : \"{TopicArn}\"" + " }" + " }" + " }" + " ]" + "}"; public static void Main(string[] args) { AmazonGlacierClient client; try { using (client = new AmazonGlacierClient(Amazon.RegionEndpoint.USWest2)) { Console.WriteLine("Setup SNS topic and SQS queue."); SetupTopicAndQueue(); Console.WriteLine("To continue, press Enter"); Console.ReadKey(); Console.WriteLine("Retrieving..."); RetrieveArchive(client); } Console.WriteLine("Operations successful. To continue, press Enter"); Console.ReadKey(); } catch (AmazonGlacierException e) { Console.WriteLine(e.Message); } catch (AmazonServiceException e) { Console.WriteLine(e.Message); } catch (Exception e) { Console.WriteLine(e.Message); } finally { // Delete SNS topic and SQS queue. snsClient.DeleteTopic(new DeleteTopicRequest() { TopicArn = topicArn }); sqsClient.DeleteQueue(new DeleteQueueRequest() { QueueUrl = queueUrl }); } } static void SetupTopicAndQueue() { snsClient = new AmazonSimpleNotificationServiceClient(Amazon.RegionEndpoint.USWest2); sqsClient = new AmazonSQSClient(Amazon.RegionEndpoint.USWest2); long ticks = DateTime.Now.Ticks; topicArn = snsClient.CreateTopic(new CreateTopicRequest { Name = "GlacierDownload-" + ticks }).TopicArn; Console.Write("topicArn: "); Console.WriteLine(topicArn); CreateQueueRequest createQueueRequest = new CreateQueueRequest(); createQueueRequest.QueueName = "GlacierDownload-" + ticks; CreateQueueResponse createQueueResponse = sqsClient.CreateQueue(createQueueRequest); queueUrl = createQueueResponse.QueueUrl; Console.Write("QueueURL: "); Console.WriteLine(queueUrl); GetQueueAttributesRequest getQueueAttributesRequest = new GetQueueAttributesRequest(); getQueueAttributesRequest.AttributeNames = new List<string> { "QueueArn" }; getQueueAttributesRequest.QueueUrl = queueUrl; GetQueueAttributesResponse response = sqsClient.GetQueueAttributes(getQueueAttributesRequest); queueArn = response.QueueARN; Console.Write("QueueArn: "); Console.WriteLine(queueArn); // Setup the Amazon SNS topic to publish to the SQS queue. snsClient.Subscribe(new SubscribeRequest() { Protocol = "sqs", Endpoint = queueArn, TopicArn = topicArn }); // Add policy to the queue so SNS can send messages to the queue. var policy = SQS_POLICY.Replace("{TopicArn}", topicArn).Replace("{QueueArn}", queueArn); sqsClient.SetQueueAttributes(new SetQueueAttributesRequest() { QueueUrl = queueUrl, Attributes = new Dictionary<string, string> { { QueueAttributeName.Policy, policy } } }); } static void RetrieveArchive(AmazonGlacierClient client) { // Initiate job. InitiateJobRequest initJobRequest = new InitiateJobRequest() { VaultName = vaultName, JobParameters = new JobParameters() { Type = "archive-retrieval", ArchiveId = archiveID, Description = "This job is to download archive.", SNSTopic = topicArn, } }; InitiateJobResponse initJobResponse = client.InitiateJob(initJobRequest); string jobId = initJobResponse.JobId; // Check queue for a message and if job completed successfully, download archive. ProcessQueue(jobId, client); } private static void ProcessQueue(string jobId, AmazonGlacierClient client) { ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest() { QueueUrl = queueUrl, MaxNumberOfMessages = 1 }; bool jobDone = false; while (!jobDone) { Console.WriteLine("Poll SQS queue"); ReceiveMessageResponse receiveMessageResponse = sqsClient.ReceiveMessage(receiveMessageRequest); if (receiveMessageResponse.Messages.Count == 0) { Thread.Sleep(10000 * 60); continue; } Console.WriteLine("Got message"); Message message = receiveMessageResponse.Messages[0]; Dictionary<string, string> outerLayer = JsonConvert.DeserializeObject<Dictionary<string, string>>(message.Body); Dictionary<string, object> fields = JsonConvert.DeserializeObject<Dictionary<string, object>>(outerLayer["Message"]); string statusCode = fields["StatusCode"] as string; if (string.Equals(statusCode, GlacierUtils.JOB_STATUS_SUCCEEDED, StringComparison.InvariantCultureIgnoreCase)) { Console.WriteLine("Downloading job output"); DownloadOutput(jobId, client); // Save job output to the specified file location. } else if (string.Equals(statusCode, GlacierUtils.JOB_STATUS_FAILED, StringComparison.InvariantCultureIgnoreCase)) Console.WriteLine("Job failed... cannot download the archive."); jobDone = true; sqsClient.DeleteMessage(new DeleteMessageRequest() { QueueUrl = queueUrl, ReceiptHandle = message.ReceiptHandle }); } } private static void DownloadOutput(string jobId, AmazonGlacierClient client) { GetJobOutputRequest getJobOutputRequest = new GetJobOutputRequest() { JobId = jobId, VaultName = vaultName }; GetJobOutputResponse getJobOutputResponse = client.GetJobOutput(getJobOutputRequest); using (Stream webStream = getJobOutputResponse.Body) { using (Stream fileToSave = File.OpenWrite(fileName)) { CopyStream(webStream, fileToSave); } } } public static void CopyStream(Stream input, Stream output) { byte[] buffer = new byte[65536]; int length; while ((length = input.Read(buffer, 0, buffer.Length)) > 0) { output.Write(buffer, 0, length); } } } }

例 2: AWS SDK for .NET の低レベル API を使用したアーカイブの取得 チャンクに分けた出力のダウンロード

次の C# コード例では、S3 Glacier からアーカイブを取得しています。このコード例では、GetJobOutputRequest オブジェクトのバイト範囲を指定することにより、ジョブの出力をチャンクに分けてダウンロードします。

using System; using System.Collections.Generic; using System.IO; using System.Threading; using Amazon.Glacier; using Amazon.Glacier.Model; using Amazon.Glacier.Transfer; using Amazon.Runtime; using Amazon.SimpleNotificationService; using Amazon.SimpleNotificationService.Model; using Amazon.SQS; using Amazon.SQS.Model; using Newtonsoft.Json; using System.Collections.Specialized; namespace glacier.amazon.com.docsamples { class ArchiveDownloadLowLevelUsingSQLSNSOutputUsingRange { static string topicArn; static string queueUrl; static string queueArn; static string vaultName = "*** Provide vault name ***"; static string archiveId = "*** Provide archive ID ***"; static string fileName = "*** Provide the file name and path to where to store downloaded archive ***"; static AmazonSimpleNotificationServiceClient snsClient; static AmazonSQSClient sqsClient; const string SQS_POLICY = "{" + " \"Version\" : \"2012-10-17\"," + " \"Statement\" : [" + " {" + " \"Sid\" : \"sns-rule\"," + " \"Effect\" : \"Allow\"," + " \"Principal\" : {\"AWS\" : \"arn:aws:iam::123456789012:root\" }," + " \"Action\" : \"sqs:SendMessage\"," + " \"Resource\" : \"{QuernArn}\"," + " \"Condition\" : {" + " \"ArnLike\" : {" + " \"aws:SourceArn\" : \"{TopicArn}\"" + " }" + " }" + " }" + " ]" + "}"; public static void Main(string[] args) { AmazonGlacierClient client; try { using (client = new AmazonGlacierClient(Amazon.RegionEndpoint.USWest2)) { Console.WriteLine("Setup SNS topic and SQS queue."); SetupTopicAndQueue(); Console.WriteLine("To continue, press Enter"); Console.ReadKey(); Console.WriteLine("Download archive"); DownloadAnArchive(archiveId, client); } Console.WriteLine("Operations successful. To continue, press Enter"); Console.ReadKey(); } catch (AmazonGlacierException e) { Console.WriteLine(e.Message); } catch (AmazonServiceException e) { Console.WriteLine(e.Message); } catch (Exception e) { Console.WriteLine(e.Message); } finally { // Delete SNS topic and SQS queue. snsClient.DeleteTopic(new DeleteTopicRequest() { TopicArn = topicArn }); sqsClient.DeleteQueue(new DeleteQueueRequest() { QueueUrl = queueUrl }); } } static void SetupTopicAndQueue() { long ticks = DateTime.Now.Ticks; // Setup SNS topic. snsClient = new AmazonSimpleNotificationServiceClient(Amazon.RegionEndpoint.USWest2); sqsClient = new AmazonSQSClient(Amazon.RegionEndpoint.USWest2); topicArn = snsClient.CreateTopic(new CreateTopicRequest { Name = "GlacierDownload-" + ticks }).TopicArn; Console.Write("topicArn: "); Console.WriteLine(topicArn); CreateQueueRequest createQueueRequest = new CreateQueueRequest(); createQueueRequest.QueueName = "GlacierDownload-" + ticks; CreateQueueResponse createQueueResponse = sqsClient.CreateQueue(createQueueRequest); queueUrl = createQueueResponse.QueueUrl; Console.Write("QueueURL: "); Console.WriteLine(queueUrl); GetQueueAttributesRequest getQueueAttributesRequest = new GetQueueAttributesRequest(); getQueueAttributesRequest.AttributeNames = new List<string> { "QueueArn" }; getQueueAttributesRequest.QueueUrl = queueUrl; GetQueueAttributesResponse response = sqsClient.GetQueueAttributes(getQueueAttributesRequest); queueArn = response.QueueARN; Console.Write("QueueArn: "); Console.WriteLine(queueArn); // Setup the Amazon SNS topic to publish to the SQS queue. snsClient.Subscribe(new SubscribeRequest() { Protocol = "sqs", Endpoint = queueArn, TopicArn = topicArn }); // Add the policy to the queue so SNS can send messages to the queue. var policy = SQS_POLICY.Replace("{TopicArn}", topicArn).Replace("{QuernArn}", queueArn); sqsClient.SetQueueAttributes(new SetQueueAttributesRequest() { QueueUrl = queueUrl, Attributes = new Dictionary<string, string> { { QueueAttributeName.Policy, policy } } }); } static void DownloadAnArchive(string archiveId, AmazonGlacierClient client) { // Initiate job. InitiateJobRequest initJobRequest = new InitiateJobRequest() { VaultName = vaultName, JobParameters = new JobParameters() { Type = "archive-retrieval", ArchiveId = archiveId, Description = "This job is to download the archive.", SNSTopic = topicArn, } }; InitiateJobResponse initJobResponse = client.InitiateJob(initJobRequest); string jobId = initJobResponse.JobId; // Check queue for a message and if job completed successfully, download archive. ProcessQueue(jobId, client); } private static void ProcessQueue(string jobId, AmazonGlacierClient client) { var receiveMessageRequest = new ReceiveMessageRequest() { QueueUrl = queueUrl, MaxNumberOfMessages = 1 }; bool jobDone = false; while (!jobDone) { Console.WriteLine("Poll SQS queue"); ReceiveMessageResponse receiveMessageResponse = sqsClient.ReceiveMessage(receiveMessageRequest); if (receiveMessageResponse.Messages.Count == 0) { Thread.Sleep(10000 * 60); continue; } Console.WriteLine("Got message"); Message message = receiveMessageResponse.Messages[0]; Dictionary<string, string> outerLayer = JsonConvert.DeserializeObject<Dictionary<string, string>>(message.Body); Dictionary<string, object> fields = JsonConvert.DeserializeObject<Dictionary<string, object>>(outerLayer["Message"]); string statusCode = fields["StatusCode"] as string; if (string.Equals(statusCode, GlacierUtils.JOB_STATUS_SUCCEEDED, StringComparison.InvariantCultureIgnoreCase)) { long archiveSize = Convert.ToInt64(fields["ArchiveSizeInBytes"]); Console.WriteLine("Downloading job output"); DownloadOutput(jobId, archiveSize, client); // This where we save job output to the specified file location. } else if (string.Equals(statusCode, GlacierUtils.JOB_STATUS_FAILED, StringComparison.InvariantCultureIgnoreCase)) Console.WriteLine("Job failed... cannot download the archive."); jobDone = true; sqsClient.DeleteMessage(new DeleteMessageRequest() { QueueUrl = queueUrl, ReceiptHandle = message.ReceiptHandle }); } } private static void DownloadOutput(string jobId, long archiveSize, AmazonGlacierClient client) { long partSize = 4 * (long)Math.Pow(2, 20); // 4 MB. using (Stream fileToSave = new FileStream(fileName, FileMode.Create, FileAccess.Write)) { long currentPosition = 0; do { GetJobOutputRequest getJobOutputRequest = new GetJobOutputRequest() { JobId = jobId, VaultName = vaultName }; long endPosition = currentPosition + partSize - 1; if (endPosition > archiveSize) endPosition = archiveSize; getJobOutputRequest.SetRange(currentPosition, endPosition); GetJobOutputResponse getJobOutputResponse = client.GetJobOutput(getJobOutputRequest); using (Stream webStream = getJobOutputResponse.Body) { CopyStream(webStream, fileToSave); } currentPosition += partSize; } while (currentPosition < archiveSize); } } public static void CopyStream(Stream input, Stream output) { byte[] buffer = new byte[65536]; int length; while ((length = input.Read(buffer, 0, buffer.Length)) > 0) { output.Write(buffer, 0, length); } } } }