AWS SDK for .NET을 사용하여 Amazon S3 Glacier에 아카이브 다운로드 - Amazon S3 Glacier

이 페이지는 저장소와 2012년부터 출시된 원본 REST API를 사용하는 S3 Glacier 서비스의 기존 고객만 이용할 수 있습니다.

아카이브 스토리지 솔루션을 찾고 있다면 Amazon S3의 S3 Glacier 스토리지 클래스, S3 Glacier 인스턴트 검색, S3 Glacier 플렉서블 검색 S3 Glacier Deep Archive를 사용하는 것이 좋습니다. 이러한 스토리지 옵션에 대한 자세한 내용은 Amazon S3 사용 설명서의 S3 Glacier 스토리지 클래스S3 Glacier 스토리지 클래스를 사용한 장기 데이터 스토리지를 참조하십시오. 이러한 스토리지 클래스는 Amazon S3 API를 사용하며, 모든 지역에서 사용할 수 있으며, Amazon S3 콘솔 내에서 관리할 수 있습니다. 스토리지 비용 분석, 스토리지 렌즈, 다중 암호화 옵션을 포함한 보안 기능 등과 같은 기능을 제공합니다.

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

AWS SDK for .NET을 사용하여 Amazon S3 Glacier에 아카이브 다운로드

.NET용 Amazon SDK에서 제공하는 하이레벨 및 로우레벨 API 둘 모두는 아카이브를 다운로드하는 방법을 제공합니다.

AWS SDK for .NET의 고레벨 API를 사용하는 아카이브 다운로드

고레벨 API의 ArchiveTransferManager 클래스는 아카이브를 다운로드하는 데 사용할 수 있는 Download 메서드를 제공합니다.

중요

ArchiveTransferManager 클래스는 Amazon Simple Notification Service(SNS) 토픽 및 해당 토픽을 구독하는 Amazon Simple Queue Service(Amazon SQS) 대기열을 생성합니다. 그런 다음 아카이브 가져오기 작업을 시작하고 아카이브를 사용할 수 있도록 대기열을 폴링합니다. 아카이브를 사용할 수 있게 되면 다운로드가 시작됩니다. 검색 시간에 대한 자세한 내용은 아카이브 검색 옵션 단원을 참조하십시오.

예제: AWS SDK for .NET의 고레벨 API를 사용하는 아카이브 다운로드

다음은 미국 서부(오레곤) 리전의 볼트(examplevault)에서 아카이브를 다운로드하는 C# 코드 예시입니다.

이 예제의 실행 방법에 대한 단계별 지침은 코드 예제 실행 단원을 참조하십시오. 코드는 기존 아카이브 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 토픽(옵션) 등 작업 정보를 제공합니다. 그러면 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~2MB의 데이터만 준비합니다.

    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(SNS) 토픽을 식별할 수 있도록 알림 구성을 설정하였거나 작업을 시작할 때 Amazon SNS 토픽을 지정하였다면 S3 Glacier가 작업 완료 후 해당 토픽에 메시지를 보냅니다. 다음 섹션에서 제공하는 코드 예시는 S3 Glacier가 메시지를 게시할 수 있도록 Amazon SNS를 사용합니다.

    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.

    특정 조건이 충족된다면 S3 Glacier가 GetJobOutput 직접 호출에 대한 응답으로 다운로드한 데이터 일부의 체크섬을 반환합니다. 자세한 내용은 데이터 다운로드 시 체크섬 수신 섹션을 참조하세요.

    다운로드에 오류가 없는지 확인하려면 클라이언트 측 체크섬을 계산한 뒤 S3 Glacier가 응답으로 보내는 체크섬과 비교합니다.

    옵션으로 범위를 지정하여 아카이브를 가져오는 작업에서는 작업 설명을 다운로드할 때 가져오는 범위에 대한 체크섬(SHA256 트리-해시)도 포함됩니다. 이 체크섬 값은 나중에 다운로드하는 전체 바이트 범위의 정확성을 검증하는 데 사용할 수 있습니다. 예를 들어 트리-해시로 정렬된 아카이브 범위를 가져오는 작업을 시작하면서 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(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를 사용하여 아카이브 검색, 청크 단위로 출력 다운로드

다음은 S3 Glacier에서 아카이브를 검색하는 C# 코드 예시입니다. 이번 코드 예제는 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); } } } }