

 **이 페이지는 볼트와 2012년부터 원래 REST API를 사용하는 Amazon Glacier 서비스의 기존 고객만 사용할 수 있습니다.**

아카이브 스토리지 솔루션을 찾고 있다면 Amazon S3의 Amazon Glacier 스토리지 클래스, S3 Glacier Instant Retrieval, S3 Glacier Flexible Retrieval 및 S3 Glacier Deep Archive를 사용하는 것이 좋습니다. 이러한 스토리지 옵션에 대한 자세한 내용은 [Amazon Glacier 스토리지 클래스](https://aws.amazon.com/s3/storage-classes/glacier/)를 참조하세요.

Amazon Glacier(기존 독립 실행형 볼트 기반 서비스)는 더 이상 신규 고객을 받지 않습니다. Amazon Glacier는 데이터를 볼트에 저장하고 Amazon S3 및 Amazon S3 Glacier 스토리지 클래스와 구별되는 자체 API를 갖춘 독립 실행형 서비스입니다. 기존 데이터는 Amazon Glacier에서 무기한으로 안전하게 보관되며 액세스 가능합니다. 마이그레이션은 필요하지 않습니다. 저비용 장기 아카이브 스토리지의 경우는 [S3 버킷 기반 API, 전체 가용성, 저렴한 비용 및 서비스 통합을 통해 우수한 고객 경험을 제공하는 Amazon S3 Glacier 스토리지 클래스](https://aws.amazon.com/s3/storage-classes/glacier/)를 AWS 권장합니다. S3 APIs AWS 리전 AWS 향상된 기능을 원하는 경우 [Amazon Glacier 볼트에서 Amazon S3 Glacier 스토리지 클래스로 데이터를 전송하기 위한AWS 솔루션 지침](https://aws.amazon.com/solutions/guidance/data-transfer-from-amazon-s3-glacier-vaults-to-amazon-s3/)을 사용하여 Amazon S3 Glacier 스토리지 클래스로 마이그레이션하는 것이 좋습니다.

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

# Amazon Glacier에서 아카이브 다운로드
<a name="downloading-an-archive"></a>

Amazon Glacier는 볼트 생성 및 삭제에 사용할 수 있는 관리 콘솔을 제공합니다. 하지만 관리 콘솔을 이용하여 Amazon Glacier에서 아카이브를 다운로드할 수는 없습니다. 사진, 비디오 및 기타 문서와 같은 데이터를 다운로드하려면 REST API를 직접 사용하거나 AWS SDKs를 사용하여 AWS Command Line Interface (AWS CLI)를 사용하거나 코드를 작성하여 요청해야 합니다.

에서 Amazon Glacier를 사용하는 방법에 대한 자세한 내용은 Amazon Glacier 참조를 AWS CLI참조하세요. [AWS CLI Amazon Glacier](https://docs.aws.amazon.com/cli/latest/reference/glacier/index.html) 를 설치하려면 단원을 AWS CLI참조하십시오[AWS Command Line Interface](https://aws.amazon.com/cli/). 다음 주제에서는 AWS SDK for Java AWS SDK for .NET, 및 Amazon Glacier REST API를 사용하여 Amazon Glacier에 아카이브를 다운로드하는 방법을 설명합니다.

**Topics**
+ [Amazon Glacier 아카이브 가져오기](downloading-an-archive-two-steps.md)
+ [를 사용하여 Amazon Glacier에서 아카이브 다운로드 AWS SDK for Java](downloading-an-archive-using-java.md)
+ [를 사용하여 Amazon Glacier에서 아카이브 다운로드 AWS SDK for .NET](downloading-an-archive-using-dotnet.md)
+ [Python을 통한 병렬 처리를 사용하여 대용량 아카이브 다운로드](downloading-large-archive-parallel-python.md)
+ [REST API를 사용하여 아카이브 다운로드](downloading-an-archive-using-rest.md)
+ [를 사용하여 Amazon Glacier에서 아카이브 다운로드 AWS CLI](downloading-an-archive-using-cli.md)

# Amazon Glacier 아카이브 가져오기
<a name="downloading-an-archive-two-steps"></a>

Amazon Glacier에서 아카이브를 가져오는 것은 비동기식 작업이기 때문에 먼저 작업을 시작하고 작업이 완료된 후에 출력을 다운로드합니다. 아카이브 가져오기 작업을 시작하려면 [작업 시작(POST jobs)](api-initiate-job-post.md) REST API 작업 또는 AWS CLI, 또는 AWS SDKs의 해당 작업을 사용합니다.

**Topics**
+ [아카이브 검색 옵션](#api-downloading-an-archive-two-steps-retrieval-options)
+ [범위가 지정된 아카이브 가져오기](#downloading-an-archive-range)

Amazon Glacier에서 아카이브를 가져오는 작업은 2단계 프로세스로 구성됩니다. 다음은 이 프로세스의 개요입니다.

**아카이브를 가져오려면**

1. 아카이브 가져오기 작업을 시작합니다.

   1. 원하는 아카이브의 ID를 가져옵니다. 아카이브 ID는 볼트 인벤토리에서 가져올 수 있습니다. REST API, AWS CLI또는 AWS SDKs. 자세한 내용은 [Amazon Glacier에서 볼트 인벤토리 다운로드](vault-inventory.md) 단원을 참조하십시오.

   1. [작업 시작(POST jobs)](api-initiate-job-post.md) 작업을 사용하여 Amazon Glacier에 후속 다운로드를 위해서 아카이브 전체 또는 일부분을 준비하도록 요청하는 작업을 시작합니다.

   작업을 시작하면 Amazon Glacier는 응답으로 작업 ID를 반환하고 비동기식으로 작업을 실행합니다. (2단계에서 설명된 것과 같이 작업이 끝날 때까지는 작업 출력을 다운로드할 수 없습니다.)
**중요**  
표준 검색에 한해서 데이터 검색 정책은 `PolicyEnforcedException` 예외에 따라 `Initiate Job` 요청이 실패하는 원인이 될 수 있습니다. 데이터 가져오기 정책에 대한 자세한 내용은 [Amazon Glacier 데이터 검색 정책](data-retrieval-policy.md) 섹션을 참조하세요. `PolicyEnforcedException` 예외에 대한 자세한 내용은 [오류 응답](api-error-responses.md) 섹션을 참조하세요.

   필요한 경우 Amazon Glacier에 저장된 대용량 데이터 세그먼트를 복원할 수 있습니다. Amazon Glacier 스토리지 클래스에서 데이터를 복원하는 방법에 대한 자세한 내용은 *Amazon Simple Storage Service 사용 설명서*의 [객체 아카이빙을 위한 스토리지 클래스]( https://docs.aws.amazon.com/AmazonS3/latest/userguide/storage-class-intro.html#sc-glacier)를 참조하세요.

1. 작업이 완료된 후 [작업 출력 가져오기(GET output)](api-job-output-get.md) 작업을 사용하여 바이트를 다운로드합니다.

   바이트 전체를 다운로드하거나, 혹은 바이트 범위를 지정하여 작업 출력의 일부만 다운로드할 수 있습니다. 출력 용량이 클수록 네트워크 장애 같은 다운로드 오류가 발생할 경우를 대비해 청크 단위로 다운로드하는 것이 효과적입니다. 단일 요청으로 작업을 출력하다가 네트워크 장애가 발생하면 출력을 처음부터 다시 다운로드해야 합니다. 하지만 청크 단위로 출력을 다운로드할 경우에는 장애가 발생하더라도 전체가 아닌 일부 출력만 다시 다운로드하면 됩니다.

Amazon Glacier에서는 출력을 다운로드하려면 작업을 먼저 마쳐야 합니다. 작업 완료 후 최소 24시간까지는 작업이 만료되지 않습니다. 이 말은 작업 완료 후 24시간까지는 출력을 다운로드할 수 있다는 것을 의미합니다. 복원은 작업 완료 후 24시간이 지나면 언제든지 만료될 수 있습니다. 작업 완료 여부를 알고 싶다면 다음 옵션 중 한 가지를 사용하여 상태를 확인합니다.
+ **작업 완료 알림 대기**: Amazon Glacier가 작업 완료 후에도 알림 메시지를 게시할 수 있도록 Amazon Simple Notification Service(Amazon SNS) 토픽을 지정합니다. Amazon Glacier는 작업이 완료된 후에만 알림을 보냅니다.

  Amazon SNS 토픽은 작업을 시작할 때 지정할 수 있습니다. 작업 요청 시 Amazon SNS 토픽을 지정하는 방법 외에 아카이브 가져오기 이벤트에 대한 알림이 볼트에 설정되어 있는 경우에도 Amazon Glacier가 알림 메시지를 해당하는 SNS 토픽에 게시합니다. 자세한 내용은 [Amazon Glacier의 볼트 알림 구성](configuring-notifications.md) 단원을 참조하십시오.
+ **명시적인 작업 정보 요청**: Amazon Glacier `Describe Job` API 작업([작업 설명(GET JobID)](api-describe-job-get.md))을 사용하여 작업 정보를 주기적으로 폴링할 수도 있습니다. 하지만 Amazon SNS 알림 메시지의 사용을 권장합니다.

**참고**  
Amazon SNS 알림을 사용하여 가져오는 정보는 `Describe Job` API 작업을 직접 호출하여 가져오는 정보와 동일합니다.

## 아카이브 검색 옵션
<a name="api-downloading-an-archive-two-steps-retrieval-options"></a>

아카이브 검색 작업을 시작할 때 액세스 시간과 비용 요건을 기준으로 다음 중 한 가지 검색 옵션을 지정할 수 있습니다. 검색 요금에 대한 자세한 내용은 [Amazon Glacier 요금](https://aws.amazon.com/s3/glacier/pricing/)을 참조하세요.
+ **신속**: 아카이브의 복원을 위한 임시 긴급 요청이 필요한 경우 신속 검색을 사용하면 S3 Glacier Flexible 검색 스토리지 클래스 또는 S3 Intelligent-Tiering 아카이브 액세스 티어에 저장된 데이터에 빠르게 액세스할 수 있습니다. 매우 큰 아카이브(250MB 이상)를 제외한 모든 경우, 신속 검색을 사용하여 액세스된 데이터는 일반적으로 1\$15분 안에 사용할 수 있습니다. 프로비저닝된 용량을 통해 필요할 때 신속 검색에 대한 검색 용량이 보장됩니다. 자세한 내용은 [프로비저닝된 용량](#api-downloading-an-archive-two-steps-retrieval-expedited-capacity) 단원을 참조하십시오.
+ **표준**: 표준 검색을 사용하면 몇 시간 내에 아카이브에 액세스할 수 있습니다. 표준 검색은 보통 3\$15시간 안에 완료됩니다. 검색 요청 시 검색 옵션을 지정하지 않을 경우 스탠다드가 기본 옵션이 됩니다.
+ **대량**: 대량 검색은 Amazon Glacier에서 가장 저렴한 검색 옵션으로 대용량 데이터, 심지어는 페타바이트 규모까지도 저렴한 비용으로 하루만에 검색할 수 있습니다. 대량 검색은 보통 5\$112시간 안에 완료됩니다.

다음 테이블에는 아카이브 검색 옵션이 요약되어 있습니다. 요금에 대한 자세한 정보는 [Amazon Glacier 요금](https://aws.amazon.com/s3/glacier/pricing/)을 참조하세요.


| 서비스 | 신속 | 표준 | 대량 | 
| --- | --- | --- | --- | 
|  Amazon Glacier  |  1\$15분  |  3\$15시간  |  5\$112시간  | 

`Expedited`, `Standard`또는 `Bulk` 검색을 수행하려면 [https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOSTrestore.html](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOSTrestore.html) REST API 작업 요청의 `Tier` 요청 요소를 원하는 옵션 또는 AWS Command Line Interface (AWS CLI) 또는 AWS SDKs의 동등한 옵션으로 설정합니다. 프로비저닝된 용량을 구매하였다면, 사용자의 프로비저닝된 용량을 통해 모든 신속 검색이 자동으로 수행됩니다.

### 프로비저닝된 용량
<a name="api-downloading-an-archive-two-steps-retrieval-expedited-capacity"></a>

프로비저닝된 용량으로 필요시에 신속 검색을 위한 검색 용량을 보장합니다. 각 용량 단위로 초당 최대 150메가바이트(MBps)의 검색 처리량이 제공되고 매 5분마다 긴급 검색을 최소 3회 수행할 수 있습니다.

워크로드에 몇 분 내로 데이터의 서브셋에 대한 신뢰성 높고 예측 가능한 액세스가 필요한 경우 프로비저닝된 검색 용량을 구매를 권장합니다. 프로비저닝된 검색 용량이 없더라도 비정상적으로 수요가 높지 않은 경우를 제외하면 일반적으로 신속 검색은 허용됩니다. 하지만 모든 상황에서 신속 검색에 액세스해야 하는 경우 프로비저닝된 검색 용량을 구매해야 합니다.

#### 프로비저닝된 용량 구매
<a name="downloading-an-archive-purchase-provisioned-capacity"></a>

Amazon Glacier 콘솔, [프로비저닝된 용량 구매(POST provisioned-capacity)](api-PurchaseProvisionedCapacity.md) REST API 작업, AWS SDKs 또는를 사용하여 프로비저닝된 용량 단위를 구매할 수 있습니다 AWS CLI. 프로비저닝된 용량의 요금에 대한 자세한 내용은 [Amazon Glacier 요금](https://aws.amazon.com/s3/glacier/pricing/)을 참조하세요.

프로비저닝된 용량 단위는 구매한 날짜 및 시간으로부터 1개월간 지속됩니다.

시작 날짜가 31일인 경우에는 만료 날짜는 다음 달 말일이 됩니다. 예를 들어 시작 날짜가 8월 31일이라면 만료 날짜는 9월 30일입니다. 시작 날짜가 1월 31일이라면 만료 날짜는 2월 28일입니다.

**Amazon Glacier 콘솔을 사용하여 프로비저닝된 용량 구매**

1.  에 로그인 AWS Management Console 하고 [https://console.aws.amazon.com/glacier/home](https://console.aws.amazon.com/glacier/home) Amazon Glacier 콘솔을 엽니다.

1. 왼쪽의 탐색 창에서 **데이터 검색 설정**을 선택합니다.

1. **프로비저닝된 용량 단위(PCU)**에서 **PCU 구매**를 선택합니다. **PCU 구매** 대화 상자가 나타납니다.

1. 프로비저닝된 용량을 구매하려는 경우 **구매 확인** 상자에 **confirm**을 입력합니다.

1.  **PCU 구매**를 선택합니다.

## 범위가 지정된 아카이브 가져오기
<a name="downloading-an-archive-range"></a>

Amazon Glacier에서 아카이브를 검색할 때는 선택사항으로 검색할 아카이브의 범위 및 부분을 지정할 수 있습니다. 기본적으로는 아카이브 전체를 가져오도록 되어 있습니다. 바이트 범위 지정은 다음과 같은 경우에 유용합니다.
+ **데이터 다운로드 관리**: Amazon Glacier는 검색 요청 완료 후 24시간 동안 검색한 데이터를 다운로드할 수 있도록 합니다. 따라서 다운로드 기간 내에 다운로드 일정을 관리할 수 있도록 아카이브에서 일부 구간만 가져올 수도 있습니다.
+ **대용량 아카이브의 타게팅된 부분만 검색**: 예를 들어, 이전에 다수의 파일을 집계하여 단일 아카이브로 업로드하였지만 지금 그 파일 중 일부만 검색하려고 하는 경우입니다. 이때는 검색 요청 한 번으로 원하는 파일이 저장된 아카이브 범위를 지정할 수 있습니다. 그렇지 않으면 가져오기 요청을 여러 차례 시작하면서 매번 1개 이상의 파일 범위를 지정해야 합니다.

범위 가져오기를 사용하여 작업을 시작할 때는 메가바이트로 정렬된 범위를 입력해야 합니다. 다시 말해서 바이트 범위는 0부터 시작하거나(아카이브의 시작 부분) 혹은 1MB 간격으로(1MB, 2MB, 3MB 등) 시작할 수 있습니다.

범위의 끝은 아카이브의 끝이거나, 범위 시작보다 1MB 단위로 큰 모든 범위일 수 있습니다. 또한 데이터를 다운로드할 때(검색 작업 완료 후) 체크섬 값까지 원하는 경우에는 작업 시작 시 요청한 범위가 트리-해시로 정렬되어야 합니다. 체크섬은 전송 중에 데이터가 손상되지 않았는지 확인할 수 있는 방법입니다. 메가바이트 정렬 및 트리-해시 정렬에 대한 자세한 내용은 [데이터 다운로드 시 체크섬 수신](checksum-calculations-range.md) 섹션을 참조하세요.

# 를 사용하여 Amazon Glacier에서 아카이브 다운로드 AWS SDK for Java
<a name="downloading-an-archive-using-java"></a>

Amazon SDK for Java에서 제공하는 [하이레벨 및 로우레벨 API](using-aws-sdk.md) 둘 모두는 아카이브를 다운로드하는 방법을 제공합니다.

**Topics**
+ [의 상위 수준 API를 사용하여 아카이브 다운로드 AWS SDK for Java](#downloading-an-archive-using-java-highlevel-api)
+ [의 하위 수준 API를 사용하여 아카이브 다운로드 AWS SDK for Java](#downloading-an-archive-using-java-lowlevel-api)

## 의 상위 수준 API를 사용하여 아카이브 다운로드 AWS SDK for Java
<a name="downloading-an-archive-using-java-highlevel-api"></a>

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

**중요**  
`ArchiveTransferManager` 클래스는 Amazon Simple Notification Service(SNS) 토픽 및 해당 토픽을 구독하는 Amazon Simple Queue Service(Amazon SQS) 대기열을 생성합니다. 그런 다음 아카이브 가져오기 작업을 시작하고 아카이브를 사용할 수 있도록 대기열을 폴링합니다. 아카이브를 사용할 수 있게 되면 다운로드가 시작됩니다. 검색 시간에 대한 자세한 내용은 [아카이브 검색 옵션](downloading-an-archive-two-steps.md#api-downloading-an-archive-two-steps-retrieval-options) 섹션을 참조하세요.

### 예:의 상위 수준 API를 사용하여 아카이브 다운로드 AWS SDK for Java
<a name="download-archives-java-highlevel-example"></a>

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

이번 샘플 실행에 대한 단계별 지침은 [Eclipse를 사용하여 Amazon Glacier의 Java 예 실행](using-aws-sdk-for-java.md#setting-up-and-testing-sdk-java) 섹션을 참조하세요. 코드는 기존 아카이브 ID와 다운로드한 아카이브를 저장할 로컬 파일 경로를 사용해 아래와 같이 업데이트해야 합니다.

**Example**  

```
import java.io.File;
import java.io.IOException;

import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.glacier.AmazonGlacierClient;
import com.amazonaws.services.glacier.transfer.ArchiveTransferManager;
import com.amazonaws.services.sns.AmazonSNSClient;
import com.amazonaws.services.sqs.AmazonSQSClient;


public class ArchiveDownloadHighLevel {
    public static String vaultName = "examplevault";
    public static String archiveId = "*** provide archive ID ***";
    public static String downloadFilePath  = "*** provide location to download archive ***";
    
    public static AmazonGlacierClient glacierClient;
    public static AmazonSQSClient sqsClient;
    public static AmazonSNSClient snsClient;
    
    public static void main(String[] args) throws IOException {
        
    	ProfileCredentialsProvider credentials = new ProfileCredentialsProvider();
        
        glacierClient = new AmazonGlacierClient(credentials);
        
        sqsClient = new AmazonSQSClient(credentials);
        snsClient = new AmazonSNSClient(credentials);
        glacierClient.setEndpoint("glacier.us-west-2.amazonaws.com");
        sqsClient.setEndpoint("sqs.us-west-2.amazonaws.com");
        snsClient.setEndpoint("sns.us-west-2.amazonaws.com");

        try {
            ArchiveTransferManager atm = new ArchiveTransferManager(glacierClient, sqsClient, snsClient);
            
            atm.download(vaultName, archiveId, new File(downloadFilePath));
            System.out.println("Downloaded file to " + downloadFilePath);
            
        } catch (Exception e)
        {
            System.err.println(e);
        }
    }
}
```

## 의 하위 수준 API를 사용하여 아카이브 다운로드 AWS SDK for Java
<a name="downloading-an-archive-using-java-lowlevel-api"></a>

다음은 AWS SDK for Java 로우레벨 API를 사용해 볼트 인벤토리를 가져오는 단계입니다.

 

1. `AmazonGlacierClient` 클래스(클라이언트)의 인스턴스를 만듭니다.

   아카이브를 다운로드할 AWS 리전을 지정해야 합니다. 이 클라이언트를 사용하여 수행하는 모든 작업은 해당 AWS 리전에 적용됩니다.

1. `initiateJob` 메서드를 실행하여 `archive-retrieval` 작업을 시작합니다.

   `InitiateJobRequest` 클래스 인스턴스를 생성하여 다운로드를 원하는 아카이브의 ID, Amazon Glacier(Amazon Glacier)가 작업 완료 메시지를 게시할 Amazon SNS 토픽(옵션) 등 작업 정보를 입력합니다. Amazon Glacier는 응답으로 작업 ID를 반환합니다. 이 응답은 `InitiateJobResult` 클래스 인스턴스에서 사용할 수 있습니다.

    

   ```
   JobParameters jobParameters = new JobParameters()
       .withArchiveId("*** provide an archive id ***")
       .withDescription("archive retrieval")
       .withRetrievalByteRange("*** provide a retrieval range***") // optional
       .withType("archive-retrieval");
   
   InitiateJobResult initiateJobResult = client.initiateJob(new InitiateJobRequest()
       .withJobParameters(jobParameters)
       .withVaultName(vaultName));  
             
   String jobId = initiateJobResult.getJobId();
   ```

   선택적으로 바이트 범위를 지정하여 Amazon Glacier가 아카이브의 일부만 준비하도록 요청할 수 있습니다. 예를 들어 다음 문을 요청에 추가하면 Amazon Glacier가 아카이브 중 1MB\$12MB만 준비하도록 요청하여 이전 요청을 업데이트할 수 있습니다.

    

   ```
   int ONE_MEG = 1048576;
   String retrievalByteRange = String.format("%s-%s", ONE_MEG, 2*ONE_MEG -1);
   
   JobParameters jobParameters = new JobParameters()
       .withType("archive-retrieval")
       .withArchiveId(archiveId)
       .withRetrievalByteRange(retrievalByteRange) 
       .withSNSTopic(snsTopicARN);
   
   InitiateJobResult initiateJobResult = client.initiateJob(new InitiateJobRequest()
       .withJobParameters(jobParameters)
       .withVaultName(vaultName));  
             
   String jobId = initiateJobResult.getJobId();
   ```

    

1.  작업이 완료될 때까지 기다립니다.

   작업 출력을 다운로드할 수 있을 때까지 기다려야 합니다. 볼트에서 Amazon Simple Notification Service(Amazon SNS) 토픽을 식별할 수 있도록 알림 구성을 설정했거나 작업을 시작할 때 Amazon SNS 토픽을 지정했다면 Amazon Glacier가 작업 완료 후 해당 토픽에 메시지를 보냅니다.

   `describeJob` 메서드를 직접 호출하여 Amazon Glacier를 폴링함으로써 작업 완료 상태를 확인하는 방법도 있습니다. 하지만 Amazon SNS 토픽의 알람을 사용해 식별하는 방법을 권장합니다.

1. `getJobOutput` 메서드를 실행하여 작업 출력(아카이브 데이터)을 다운로드합니다.

   `GetJobOutputRequest` 클래스 인스턴스를 생성하여 작업 ID, 볼트 이름 등 요청 정보를 입력합니다. Amazon Glacier가 반환하는 출력은 `GetJobOutputResult` 객체에서 사용할 수 있습니다.

    

   ```
   GetJobOutputRequest jobOutputRequest = new GetJobOutputRequest()
           .withJobId("*** provide a job ID ***")
           .withVaultName("*** provide a vault name ****");
   GetJobOutputResult jobOutputResult = client.getJobOutput(jobOutputRequest);
   
   // jobOutputResult.getBody() // Provides the input stream.
   ```

   위의 코드 조각은 전체 작업 출력을 다운로드합니다. 옵션으로 `GetJobOutputRequest`에서 바이트 범위를 지정하여 출력 일부만 가져오거나 전체 출력을 더 작은 청크 단위로 나누어 다운로드할 수 있습니다.

    

   ```
   GetJobOutputRequest jobOutputRequest = new GetJobOutputRequest()
           .withJobId("*** provide a job ID ***")
           .withRange("bytes=0-1048575")   // Download only the first 1 MB of the output.
           .withVaultName("*** provide a vault name ****");
   ```

   특정 조건이 충족된다면 Amazon Glacier가 `GetJobOutput` 직접 호출에 대한 응답으로 다운로드한 데이터 일부의 체크섬을 반환합니다. 자세한 내용은 [데이터 다운로드 시 체크섬 수신](checksum-calculations-range.md) 단원을 참조하십시오.

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

   아카이브 가져오기 작업에서 옵션으로 범위를 지정한 경우에는 작업 설명에 가져오는 범위의 체크섬도 포함됩니다(SHA256TreeHash). 이 값은 나중에 다운로드하는 전체 바이트 범위의 정확성을 검증하는 데도 사용할 수 있습니다. 예를 들어 트리-해시로 정렬된 아카이브 범위를 가져오는 작업을 시작하면서 `GetJobOutput` 요청이 각각 체크섬을 반환할 수 있도록 청크 단위로 출력을 다운로드하는 경우에는 클라이언트 측에서 다운로드하는 개별 데이터의 체크섬을 계산하고 나서 트리 해시를 계산할 수 있습니다. Amazon Glacier가 작업 설명 요청에 대한 응답으로 반환하는 체크섬과 비교하여 사용자가 다운로드한 전체 바이트 범위가 Amazon Glacier에 저장된 바이트 범위와 일치하는지 확인할 수 있습니다.

    사용 가능한 예제는 [예제 2:의 하위 수준 API를 사용하여 아카이브 검색 AWS SDK for Java- 청크 단위로 출력 다운로드](#downloading-an-archive-with-range-using-java-example) 섹션을 참조하세요.

### 예제 1:의 하위 수준 API를 사용하여 아카이브 검색 AWS SDK for Java
<a name="downloading-an-archive-using-java-example"></a>

다음은 지정된 볼트에서 아카이브를 다운로드하는 Java 코드 예제입니다. 작업을 마치면 `getJobOutput` 호출 한 번으로 전체 출력을 다운로드합니다. 출력을 청크 단위로 다운로드하는 예제는 [예제 2:의 하위 수준 API를 사용하여 아카이브 검색 AWS SDK for Java- 청크 단위로 출력 다운로드](#downloading-an-archive-with-range-using-java-example) 섹션을 참조하세요.

이 예에서는 다음과 같은 작업을 수행합니다.

 
+ Amazon Simple Notification Service(Amazon SNS) 토픽을 생성합니다.

  Amazon Glacier는 작업 완료 후 해당 토픽에 알림을 전송합니다.
+ Amazon Simple Queue Service(Amazon SQS) 대기열을 생성합니다.

  아래 예시는 Amazon SNS 토픽이 메시지를 대기열에 게시할 수 있도록 여기에서 해당 대기열에 정책을 연결합니다.
+ 지정된 아카이브의 다운로드 작업을 시작합니다.

  작업 요청에서 Amazon Glacier가 작업 완료 후 알림 메시지를 해당 토픽에 게시할 수 있도록 생성된 Amazon SNS 토픽이 지정됩니다.
+ 작업 ID가 포함된 메시지가 있는지 Amazon SQS 대기열을 주기적으로 확인합니다.

  메시지가 있으면 JSON 구문을 분석하여 작업이 성공적으로 완료되었는지 확인합니다. 성공적으로 완료되었으면 아카이브를 다운로드합니다.
+ Amazon SNS 토픽과 생성된 Amazon SQS 대기열을 삭제하여 정리합니다.

 

```
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.map.ObjectMapper;

import com.amazonaws.AmazonClientException;
import com.amazonaws.auth.policy.Policy;
import com.amazonaws.auth.policy.Principal;
import com.amazonaws.auth.policy.Resource;
import com.amazonaws.auth.policy.Statement;
import com.amazonaws.auth.policy.Statement.Effect;
import com.amazonaws.auth.policy.actions.SQSActions;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.glacier.AmazonGlacierClient;
import com.amazonaws.services.glacier.model.GetJobOutputRequest;
import com.amazonaws.services.glacier.model.GetJobOutputResult;
import com.amazonaws.services.glacier.model.InitiateJobRequest;
import com.amazonaws.services.glacier.model.InitiateJobResult;
import com.amazonaws.services.glacier.model.JobParameters;
import com.amazonaws.services.sns.AmazonSNSClient;
import com.amazonaws.services.sns.model.CreateTopicRequest;
import com.amazonaws.services.sns.model.CreateTopicResult;
import com.amazonaws.services.sns.model.DeleteTopicRequest;
import com.amazonaws.services.sns.model.SubscribeRequest;
import com.amazonaws.services.sns.model.SubscribeResult;
import com.amazonaws.services.sns.model.UnsubscribeRequest;
import com.amazonaws.services.sqs.AmazonSQSClient;
import com.amazonaws.services.sqs.model.CreateQueueRequest;
import com.amazonaws.services.sqs.model.CreateQueueResult;
import com.amazonaws.services.sqs.model.DeleteQueueRequest;
import com.amazonaws.services.sqs.model.GetQueueAttributesRequest;
import com.amazonaws.services.sqs.model.GetQueueAttributesResult;
import com.amazonaws.services.sqs.model.Message;
import com.amazonaws.services.sqs.model.ReceiveMessageRequest;
import com.amazonaws.services.sqs.model.SetQueueAttributesRequest;


public class AmazonGlacierDownloadArchiveWithSQSPolling {
    
    public static String archiveId = "*** provide archive ID ****";
    public static String vaultName = "*** provide vault name ***";
    public static String snsTopicName = "*** provide topic name ***";
    public static String sqsQueueName = "*** provide queue name ***";
    public static String sqsQueueARN;
    public static String sqsQueueURL;
    public static String snsTopicARN;
    public static String snsSubscriptionARN;
    public static String fileName = "*** provide file name ***";
    public static String region = "*** region ***"; 
    public static long sleepTime = 600; 
    public static AmazonGlacierClient client;
    public static AmazonSQSClient sqsClient;
    public static AmazonSNSClient snsClient;
    
    public static void main(String[] args) throws IOException {
        
    	ProfileCredentialsProvider credentials = new ProfileCredentialsProvider();

        client = new AmazonGlacierClient(credentials);
        client.setEndpoint("https://glacier." + region + ".amazonaws.com");
        sqsClient = new AmazonSQSClient(credentials);
        sqsClient.setEndpoint("https://sqs." + region + ".amazonaws.com");
        snsClient = new AmazonSNSClient(credentials);
        snsClient.setEndpoint("https://sns." + region + ".amazonaws.com");
                
        try {
            setupSQS();
            
            setupSNS();

            String jobId = initiateJobRequest();
            System.out.println("Jobid = " + jobId);
            
            Boolean success = waitForJobToComplete(jobId, sqsQueueURL);
            if (!success) { throw new Exception("Job did not complete successfully."); }
            
            downloadJobOutput(jobId);
            
            cleanUp();
            
        } catch (Exception e) {
            System.err.println("Archive retrieval failed.");
            System.err.println(e);
        }   
    }

    private static void setupSQS() {
        CreateQueueRequest request = new CreateQueueRequest()
            .withQueueName(sqsQueueName);
        CreateQueueResult result = sqsClient.createQueue(request);  
        sqsQueueURL = result.getQueueUrl();
                
        GetQueueAttributesRequest qRequest = new GetQueueAttributesRequest()
            .withQueueUrl(sqsQueueURL)
            .withAttributeNames("QueueArn");
        
        GetQueueAttributesResult qResult = sqsClient.getQueueAttributes(qRequest);
        sqsQueueARN = qResult.getAttributes().get("QueueArn");
        
        Policy sqsPolicy = 
            new Policy().withStatements(
                    new Statement(Effect.Allow)
                    .withPrincipals(Principal.AllUsers)
                    .withActions(SQSActions.SendMessage)
                    .withResources(new Resource(sqsQueueARN)));
        Map<String, String> queueAttributes = new HashMap<String, String>();
        queueAttributes.put("Policy", sqsPolicy.toJson());
        sqsClient.setQueueAttributes(new SetQueueAttributesRequest(sqsQueueURL, queueAttributes)); 

    }
    private static void setupSNS() {
        CreateTopicRequest request = new CreateTopicRequest()
            .withName(snsTopicName);
        CreateTopicResult result = snsClient.createTopic(request);
        snsTopicARN = result.getTopicArn();

        SubscribeRequest request2 = new SubscribeRequest()
            .withTopicArn(snsTopicARN)
            .withEndpoint(sqsQueueARN)
            .withProtocol("sqs");
        SubscribeResult result2 = snsClient.subscribe(request2);
                
        snsSubscriptionARN = result2.getSubscriptionArn();
    }
    private static String initiateJobRequest() {
        
        JobParameters jobParameters = new JobParameters()
            .withType("archive-retrieval")
            .withArchiveId(archiveId)
            .withSNSTopic(snsTopicARN);
        
        InitiateJobRequest request = new InitiateJobRequest()
            .withVaultName(vaultName)
            .withJobParameters(jobParameters);
        
        InitiateJobResult response = client.initiateJob(request);
        
        return response.getJobId();
    }
    
    private static Boolean waitForJobToComplete(String jobId, String sqsQueueUrl) throws InterruptedException, JsonParseException, IOException {
        
        Boolean messageFound = false;
        Boolean jobSuccessful = false;
        ObjectMapper mapper = new ObjectMapper();
        JsonFactory factory = mapper.getJsonFactory();
        
        while (!messageFound) {
            List<Message> msgs = sqsClient.receiveMessage(
               new ReceiveMessageRequest(sqsQueueUrl).withMaxNumberOfMessages(10)).getMessages();

            if (msgs.size() > 0) {
                for (Message m : msgs) {
                    JsonParser jpMessage = factory.createJsonParser(m.getBody());
                    JsonNode jobMessageNode = mapper.readTree(jpMessage);
                    String jobMessage = jobMessageNode.get("Message").getTextValue();
                    
                    JsonParser jpDesc = factory.createJsonParser(jobMessage);
                    JsonNode jobDescNode = mapper.readTree(jpDesc);
                    String retrievedJobId = jobDescNode.get("JobId").getTextValue();
                    String statusCode = jobDescNode.get("StatusCode").getTextValue();
                    if (retrievedJobId.equals(jobId)) {
                        messageFound = true;
                        if (statusCode.equals("Succeeded")) {
                            jobSuccessful = true;
                        }
                    }
                }
                
            } else {
              Thread.sleep(sleepTime * 1000); 
            }
          }
        return (messageFound && jobSuccessful);
    }
    
    private static void downloadJobOutput(String jobId) throws IOException {
        
        GetJobOutputRequest getJobOutputRequest = new GetJobOutputRequest()
            .withVaultName(vaultName)
            .withJobId(jobId);
        GetJobOutputResult getJobOutputResult = client.getJobOutput(getJobOutputRequest);
    
        InputStream input = new BufferedInputStream(getJobOutputResult.getBody());
        OutputStream output = null;
        try {
            output = new BufferedOutputStream(new FileOutputStream(fileName));

            byte[] buffer = new byte[1024 * 1024];

            int bytesRead = 0;
            do {
                bytesRead = input.read(buffer);
                if (bytesRead <= 0) break;
                output.write(buffer, 0, bytesRead);
            } while (bytesRead > 0);
        } catch (IOException e) {
            throw new AmazonClientException("Unable to save archive", e);
        } finally {
            try {input.close();}  catch (Exception e) {}
            try {output.close();} catch (Exception e) {}
        }
        System.out.println("Retrieved archive to " + fileName);
    }
    
    private static void cleanUp() {
        snsClient.unsubscribe(new UnsubscribeRequest(snsSubscriptionARN));
        snsClient.deleteTopic(new DeleteTopicRequest(snsTopicARN));
        sqsClient.deleteQueue(new DeleteQueueRequest(sqsQueueURL));
    }
}
```

### 예제 2:의 하위 수준 API를 사용하여 아카이브 검색 AWS SDK for Java- 청크 단위로 출력 다운로드
<a name="downloading-an-archive-with-range-using-java-example"></a>

다음은 Amazon Glacier에서 아카이브를 검색하는 Java 코드 예입니다. 이 코드 예제는 `GetJobOutputRequest` 객체에서 바이트 범위를 지정하여 작업 출력을 청크 단위로 다운로드합니다.

 

```
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import com.amazonaws.auth.policy.Policy;
import com.amazonaws.auth.policy.Principal;
import com.amazonaws.auth.policy.Resource;
import com.amazonaws.auth.policy.Statement;
import com.amazonaws.auth.policy.Statement.Effect;
import com.amazonaws.auth.policy.actions.SQSActions;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.glacier.AmazonGlacierClient;
import com.amazonaws.services.glacier.TreeHashGenerator;
import com.amazonaws.services.glacier.model.GetJobOutputRequest;
import com.amazonaws.services.glacier.model.GetJobOutputResult;
import com.amazonaws.services.glacier.model.InitiateJobRequest;
import com.amazonaws.services.glacier.model.InitiateJobResult;
import com.amazonaws.services.glacier.model.JobParameters;
import com.amazonaws.services.sns.AmazonSNSClient;
import com.amazonaws.services.sns.model.CreateTopicRequest;
import com.amazonaws.services.sns.model.CreateTopicResult;
import com.amazonaws.services.sns.model.DeleteTopicRequest;
import com.amazonaws.services.sns.model.SubscribeRequest;
import com.amazonaws.services.sns.model.SubscribeResult;
import com.amazonaws.services.sns.model.UnsubscribeRequest;
import com.amazonaws.services.sqs.AmazonSQSClient;
import com.amazonaws.services.sqs.model.CreateQueueRequest;
import com.amazonaws.services.sqs.model.CreateQueueResult;
import com.amazonaws.services.sqs.model.DeleteQueueRequest;
import com.amazonaws.services.sqs.model.GetQueueAttributesRequest;
import com.amazonaws.services.sqs.model.GetQueueAttributesResult;
import com.amazonaws.services.sqs.model.Message;
import com.amazonaws.services.sqs.model.ReceiveMessageRequest;
import com.amazonaws.services.sqs.model.SetQueueAttributesRequest;


public class ArchiveDownloadLowLevelWithRange {
    
    public static String vaultName = "*** provide vault name ***";
    public static String archiveId = "*** provide archive id ***";
    public static String snsTopicName = "glacier-temp-sns-topic";
    public static String sqsQueueName = "glacier-temp-sqs-queue";
    public static long downloadChunkSize = 4194304; // 4 MB  
    public static String sqsQueueARN;
    public static String sqsQueueURL;
    public static String snsTopicARN;
    public static String snsSubscriptionARN;
    public static String fileName = "*** provide file name to save archive to ***";
    public static String region   = "*** region ***";
    public static long sleepTime  = 600; 
    
    public static AmazonGlacierClient client;
    public static AmazonSQSClient sqsClient;
    public static AmazonSNSClient snsClient; 
    
    public static void main(String[] args) throws IOException {
        
    	ProfileCredentialsProvider credentials = new ProfileCredentialsProvider();

        client = new AmazonGlacierClient(credentials);
        client.setEndpoint("https://glacier." + region + ".amazonaws.com");
        sqsClient = new AmazonSQSClient(credentials);
        sqsClient.setEndpoint("https://sqs." + region + ".amazonaws.com");
        snsClient = new AmazonSNSClient(credentials);
        snsClient.setEndpoint("https://sns." + region + ".amazonaws.com");
        
        try {
            setupSQS();
            
            setupSNS();

            String jobId = initiateJobRequest();
            System.out.println("Jobid = " + jobId);
            
            long archiveSizeInBytes = waitForJobToComplete(jobId, sqsQueueURL);
            if (archiveSizeInBytes==-1) { throw new Exception("Job did not complete successfully."); }
            
            downloadJobOutput(jobId, archiveSizeInBytes);
            
            cleanUp();
            
        } catch (Exception e) {
            System.err.println("Archive retrieval failed.");
            System.err.println(e);
        }   
    }

    private static void setupSQS() {
        CreateQueueRequest request = new CreateQueueRequest()
            .withQueueName(sqsQueueName);
        CreateQueueResult result = sqsClient.createQueue(request);  
        sqsQueueURL = result.getQueueUrl();
                
        GetQueueAttributesRequest qRequest = new GetQueueAttributesRequest()
            .withQueueUrl(sqsQueueURL)
            .withAttributeNames("QueueArn");
        
        GetQueueAttributesResult qResult = sqsClient.getQueueAttributes(qRequest);
        sqsQueueARN = qResult.getAttributes().get("QueueArn");
        
        Policy sqsPolicy = 
            new Policy().withStatements(
                    new Statement(Effect.Allow)
                    .withPrincipals(Principal.AllUsers)
                    .withActions(SQSActions.SendMessage)
                    .withResources(new Resource(sqsQueueARN)));
        Map<String, String> queueAttributes = new HashMap<String, String>();
        queueAttributes.put("Policy", sqsPolicy.toJson());
        sqsClient.setQueueAttributes(new SetQueueAttributesRequest(sqsQueueURL, queueAttributes)); 

    }
    private static void setupSNS() {
        CreateTopicRequest request = new CreateTopicRequest()
            .withName(snsTopicName);
        CreateTopicResult result = snsClient.createTopic(request);
        snsTopicARN = result.getTopicArn();

        SubscribeRequest request2 = new SubscribeRequest()
            .withTopicArn(snsTopicARN)
            .withEndpoint(sqsQueueARN)
            .withProtocol("sqs");
        SubscribeResult result2 = snsClient.subscribe(request2);
                
        snsSubscriptionARN = result2.getSubscriptionArn();
    }
    private static String initiateJobRequest() {
        
        JobParameters jobParameters = new JobParameters()
            .withType("archive-retrieval")
            .withArchiveId(archiveId)
            .withSNSTopic(snsTopicARN);
        
        InitiateJobRequest request = new InitiateJobRequest()
            .withVaultName(vaultName)
            .withJobParameters(jobParameters);
        
        InitiateJobResult response = client.initiateJob(request);
        
        return response.getJobId();
    }
    
    private static long waitForJobToComplete(String jobId, String sqsQueueUrl) throws InterruptedException, JsonParseException, IOException {
        
        Boolean messageFound = false;
        Boolean jobSuccessful = false;
        long archiveSizeInBytes = -1;
        ObjectMapper mapper = new ObjectMapper();
        JsonFactory factory = mapper.getFactory();
        
        while (!messageFound) {
            List<Message> msgs = sqsClient.receiveMessage(
               new ReceiveMessageRequest(sqsQueueUrl).withMaxNumberOfMessages(10)).getMessages();

            if (msgs.size() > 0) {
                for (Message m : msgs) {
                    JsonParser jpMessage = factory.createJsonParser(m.getBody());
                    JsonNode jobMessageNode = mapper.readTree(jpMessage);
                    String jobMessage = jobMessageNode.get("Message").textValue();
                    
                    JsonParser jpDesc = factory.createJsonParser(jobMessage);
                    JsonNode jobDescNode = mapper.readTree(jpDesc);
                    String retrievedJobId = jobDescNode.get("JobId").textValue();
                    String statusCode = jobDescNode.get("StatusCode").textValue();
                    archiveSizeInBytes = jobDescNode.get("ArchiveSizeInBytes").longValue();
                    if (retrievedJobId.equals(jobId)) {
                        messageFound = true;
                        if (statusCode.equals("Succeeded")) {
                            jobSuccessful = true;
                        }
                    }
                }
                
            } else {
              Thread.sleep(sleepTime * 1000); 
            }
          }
        return (messageFound && jobSuccessful) ? archiveSizeInBytes : -1;
    }
    
    private static void downloadJobOutput(String jobId, long archiveSizeInBytes) throws IOException {
        
        if (archiveSizeInBytes < 0) {
            System.err.println("Nothing to download.");
            return;
        }

        System.out.println("archiveSizeInBytes: " + archiveSizeInBytes);
        FileOutputStream fstream = new FileOutputStream(fileName);
        long startRange = 0;
        long endRange = (downloadChunkSize > archiveSizeInBytes) ? archiveSizeInBytes -1 : downloadChunkSize - 1;

        do {

            GetJobOutputRequest getJobOutputRequest = new GetJobOutputRequest()
                .withVaultName(vaultName)
                .withRange("bytes=" + startRange + "-" + endRange)
                .withJobId(jobId);
            GetJobOutputResult getJobOutputResult = client.getJobOutput(getJobOutputRequest);

            BufferedInputStream is = new BufferedInputStream(getJobOutputResult.getBody());     
            byte[] buffer = new byte[(int)(endRange - startRange + 1)];

            System.out.println("Checksum received: " + getJobOutputResult.getChecksum());
            System.out.println("Content range " + getJobOutputResult.getContentRange());

            
            int totalRead = 0;
            while (totalRead < buffer.length) {
                int bytesRemaining = buffer.length - totalRead;
                int read = is.read(buffer, totalRead, bytesRemaining);
                if (read > 0) {
                    totalRead = totalRead + read;                             
                } else {
                    break;
                }
                
            }
            System.out.println("Calculated checksum: " + TreeHashGenerator.calculateTreeHash(new ByteArrayInputStream(buffer)));
            System.out.println("read = " + totalRead);
            fstream.write(buffer);
            
            startRange = startRange + (long)totalRead;
            endRange = ((endRange + downloadChunkSize) >  archiveSizeInBytes) ? archiveSizeInBytes : (endRange + downloadChunkSize); 
            is.close();
        } while (endRange <= archiveSizeInBytes  && startRange < archiveSizeInBytes);
        
        fstream.close();
        System.out.println("Retrieved file to " + fileName);

    }
    
    private static void cleanUp() {
        snsClient.unsubscribe(new UnsubscribeRequest(snsSubscriptionARN));
        snsClient.deleteTopic(new DeleteTopicRequest(snsTopicARN));
        sqsClient.deleteQueue(new DeleteQueueRequest(sqsQueueURL));
    }
}
```

# 를 사용하여 Amazon Glacier에서 아카이브 다운로드 AWS SDK for .NET
<a name="downloading-an-archive-using-dotnet"></a>

Amazon SDK for .NET에서 제공하는 [하이레벨 및 로우레벨 API](using-aws-sdk.md) 둘 모두는 아카이브를 다운로드하는 방법을 제공합니다.

**Topics**
+ [의 상위 수준 API를 사용하여 아카이브 다운로드 AWS SDK for .NET](#downloading-an-archive-using-dotnet-highlevel-api)
+ [의 하위 수준 API를 사용하여 아카이브 다운로드 AWS SDK for .NET](#downloading-an-archive-using-dotnet-lowlevel-api)

## 의 상위 수준 API를 사용하여 아카이브 다운로드 AWS SDK for .NET
<a name="downloading-an-archive-using-dotnet-highlevel-api"></a>

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

**중요**  
`ArchiveTransferManager` 클래스는 Amazon Simple Notification Service(SNS) 토픽 및 해당 토픽을 구독하는 Amazon Simple Queue Service(Amazon SQS) 대기열을 생성합니다. 그런 다음 아카이브 가져오기 작업을 시작하고 아카이브를 사용할 수 있도록 대기열을 폴링합니다. 아카이브를 사용할 수 있게 되면 다운로드가 시작됩니다. 검색 시간에 대한 자세한 내용은 [아카이브 검색 옵션](downloading-an-archive-two-steps.md#api-downloading-an-archive-two-steps-retrieval-options) 섹션을 참조하세요.

### 예:의 상위 수준 API를 사용하여 아카이브 다운로드 AWS SDK for .NET
<a name="download-archives-dotnet-highlevel-example"></a>

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

이 예제의 실행 방법에 대한 단계별 지침은 [코드 예제 실행](using-aws-sdk-for-dot-net.md#setting-up-and-testing-sdk-dotnet) 섹션을 참조하세요. 코드는 기존 아카이브 ID와 다운로드한 아카이브를 저장할 로컬 파일 경로를 사용해 아래와 같이 업데이트해야 합니다.

```
using System;
using Amazon.Glacier;
using Amazon.Glacier.Transfer;
using Amazon.Runtime;

namespace glacier.amazon.com.rproxy.govskope.us.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);
      }
    }
  }
}
```

## 의 하위 수준 API를 사용하여 아카이브 다운로드 AWS SDK for .NET
<a name="downloading-an-archive-using-dotnet-lowlevel-api"></a>

다음은 AWS SDK for .NET의 로우레벨 API를 사용해 Amazon Glacier(Amazon Glacier) 아카이브를 다운로드하는 단계입니다.

1. `AmazonGlacierClient` 클래스(클라이언트)의 인스턴스를 만듭니다.

   아카이브를 다운로드할 AWS 리전을 지정해야 합니다. 이 클라이언트를 사용하여 수행하는 모든 작업은 해당 AWS 리전에 적용됩니다.

1. `InitiateJob` 메서드를 실행하여 `archive-retrieval` 작업을 시작합니다.

   `InitiateJobRequest` 클래스 인스턴스를 생성하여 다운로드를 원하는 아카이브의 ID, Amazon Glacier가 작업 완료 메시지를 게시할 Amazon SNS 토픽(옵션) 등 작업 정보를 제공합니다. Amazon 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;
   ```

   다음 요청과 같이 선택적으로 바이트 범위를 지정하여 Amazon Glacier에 아카이브의 일부만 준비하도록 요청할 수 있습니다. 그러면 Amazon Glacier는 요청이 지정한 바에 따라 아카이브에서 1\$12MB의 데이터만 준비합니다.

   ```
   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;
   ```

1.  작업이 완료될 때까지 기다립니다.

   작업 출력을 다운로드할 수 있을 때까지 기다려야 합니다. 볼트에서 Amazon Simple Notification Service(Amazon SNS) 토픽을 식별할 수 있도록 알림 구성을 설정했거나 작업을 시작할 때 Amazon SNS 토픽을 지정했다면 Amazon Glacier가 작업 완료 후 해당 토픽에 메시지를 보냅니다. 다음 섹션에서 제공하는 코드 예시는 Amazon Glacier가 메시지를 게시할 수 있도록 Amazon SNS를 사용합니다.

   `DescribeJob` 메서드를 직접 호출하여 Amazon Glacier를 폴링함으로써 작업 완료 상태를 확인하는 방법도 있습니다. 하지만 Amazon SNS 토픽의 알림을 사용해 식별하는 방법이 권장됩니다.

1. `GetJobOutput` 메서드를 실행하여 작업 출력(아카이브 데이터)을 다운로드합니다.

   `GetJobOutputRequest` 클래스 인스턴스를 생성하여 작업 ID, 볼트 이름 등 요청 정보를 입력합니다. Amazon 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.
   ```

   특정 조건이 충족된다면 Amazon Glacier가 `GetJobOutput` 직접 호출에 대한 응답으로 다운로드한 데이터 일부의 체크섬을 반환합니다. 자세한 내용은 [데이터 다운로드 시 체크섬 수신](checksum-calculations-range.md) 단원을 참조하십시오.

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

   옵션으로 범위를 지정하여 아카이브를 가져오는 작업에서는 작업 설명을 다운로드할 때 가져오는 범위에 대한 체크섬(SHA256 트리-해시)도 포함됩니다. 이 체크섬 값은 나중에 다운로드하는 전체 바이트 범위의 정확성을 검증하는 데 사용할 수 있습니다. 예를 들어 트리-해시로 정렬된 아카이브 범위를 가져오는 작업을 시작하면서 `GetJobOutput` 요청이 각각 체크섬을 반환할 수 있도록 청크 단위로 출력을 다운로드하는 경우에는 클라이언트 측에서 다운로드하는 개별 데이터의 체크섬을 계산하고 나서 트리 해시를 계산할 수 있습니다. Amazon Glacier가 작업 설명 요청에 대한 응답으로 반환하는 체크섬과 비교하여 사용자가 다운로드한 전체 바이트 범위가 Amazon Glacier에 저장된 바이트 범위와 일치하는지 확인할 수 있습니다.

   

   사용 가능한 예제는 [예제 2:의 하위 수준 API를 사용하여 아카이브 검색 AWS SDK for .NET- 청크 단위로 출력 다운로드](#creating-vaults-sdk-dotnet-example2) 섹션을 참조하세요.

### 예제 1:의 하위 수준 API를 사용하여 아카이브 검색 AWS SDK for .NET
<a name="creating-vaults-sdk-dotnet-example-retrieve"></a>

다음은 지정된 볼트에서 아카이브를 다운로드하는 C\$1 코드 예제입니다. 작업을 마치면 `GetJobOutput` 호출 한 번으로 전체 출력을 다운로드합니다. 출력을 청크 단위로 다운로드하는 예제는 [예제 2:의 하위 수준 API를 사용하여 아카이브 검색 AWS SDK for .NET- 청크 단위로 출력 다운로드](#creating-vaults-sdk-dotnet-example2) 섹션을 참조하세요.

이 예에서는 다음과 같은 작업을 수행합니다.
+ Amazon Simple Notification Service(Amazon SNS) 토픽 설정 

  Amazon Glacier는 작업 완료 후 해당 토픽에 알림을 전송합니다.
+ Amazon Simple Queue Service(Amazon SQS) 대기열을 설정합니다.

  아래 예시는 Amazon SNS 토픽이 메시지를 게시할 수 있도록 대기열에 정책을 연결합니다.
+ 지정된 아카이브의 다운로드 작업을 시작합니다.

  아래 예시는 Amazon Glacier가 작업 완료 후 메시지를 전송할 수 있도록 작업 요청에서 Amazon SNS 토픽을 지정합니다.
+ Amazon SQS 대기열의 메시지를 주기적으로 확인합니다.

  메시지가 있으면 JSON 구문을 분석하여 작업이 성공적으로 완료되었는지 확인합니다. 성공적으로 완료되었으면 아카이브를 다운로드합니다. 아래 코드 예제에서는 JSON.NET 라이브러리([JSON.NET](http://json.codeplex.com/) 참조)를 사용하여 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.rproxy.govskope.us.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\",&TCX5-2025-waiver;" +
        "    \"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:의 하위 수준 API를 사용하여 아카이브 검색 AWS SDK for .NET- 청크 단위로 출력 다운로드
<a name="creating-vaults-sdk-dotnet-example2"></a>

다음은 Amazon Glacier에서 아카이브를 검색하는 C\$1 코드 예입니다. 이 코드 예제는 `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.rproxy.govskope.us.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\",&TCX5-2025-waiver;" +
        "    \"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);
      }
    }
  }
}
```

# Python을 통한 병렬 처리를 사용하여 대용량 아카이브 다운로드
<a name="downloading-large-archive-parallel-python"></a>

이 주제에서는 Python을 통한 병렬 처리를 사용하여 Amazon S3 Glacier(S3 Glacier)에서 대용량 아카이브를 다운로드하는 방법을 설명합니다. 이 접근 방식을 사용하면 아카이브를 독립적으로 처리할 수 있는 작은 조각으로 나누어 원하는 크기의 아카이브를 안정적으로 다운로드할 수 있습니다.

## 개요
<a name="downloading-large-archive-python-overview"></a>

이 예제에 제공된 Python 스크립트는 다음 작업을 수행합니다.

1. 알림에 필요한 AWS 리소스(Amazon SNS 주제 및 Amazon SQS 대기열)를 설정합니다.

1. Amazon Glacier에서 아카이브 가져오기 작업을 시작합니다.

1. Amazon SQS 대기열에서 작업 완료 알림을 모니터링합니다.

1. 대용량 아카이브를 관리 가능한 청크로 분할합니다.

1. 여러 작업자 스레드를 사용하여 청크를 병렬로 다운로드합니다.

1. 나중에 다시 조립할 수 있도록 각 청크를 디스크에 저장합니다.

## 사전 조건
<a name="downloading-large-archive-python-prerequisites"></a>

시작하기 전에, 다음 사항을 확인해야 합니다.
+ Python 3.6 이상 설치
+ AWS SDK for Python(Boto3) 설치됨
+ AWS Amazon Glacier, Amazon SNS 및 Amazon SQS에 대한 적절한 권한으로 구성된 자격 증명
+ 다운로드한 아카이브 청크를 저장하기에 충분한 디스크 공간

## 예: Python을 통한 병렬 처리를 사용하여 아카이브 다운로드
<a name="downloading-large-archive-python-code"></a>

다음 Python 스크립트는 병렬 처리를 사용하여 Amazon Glacier에서 대용량 아카이브를 다운로드하는 방법을 보여줍니다.

```
import boto3
import time
import json
import jmespath
import re
import concurrent.futures
import os

output_file_path = "output_directory_path"
vault_name = "vault_name"

chunk_size = 1000000000 #1gb - size of chunks for parallel download.
notify_queue_name = 'GlacierJobCompleteNotifyQueue' # SQS queue for Glacier recall notification
chunk_download_queue_name='GlacierChunkReadyNotifyQueue' # SQS queue for chunks
sns_topic_name = 'GlacierRecallJobCompleted' # the SNS topic to be notified when Glacier archive is restored.
chunk_queue_visibility_timeout = 7200 # 2 hours - this may need to be adjusted.
region = 'us-east-1'
archive_id = "archive_id_to_restore"
retrieve_archive = True # set to false if you do not want to restore from Glacier - useful for restarting or parallel processing of the chunk queue.
workers = 12 # the number of parallel worker threads for downloading chunks. 

def setup_queues_and_topic():
    sqs = boto3.client('sqs')
    sns = boto3.client('sns')

    # Create the SNS topic
    topic_response = sns.create_topic(
        Name=sns_topic_name
    )
    topic_arn = topic_response['TopicArn']
    print("Creating the SNS topic " + topic_arn)

    # Create the notification queue
    notify_queue_response = sqs.create_queue(
        QueueName=notify_queue_name,
        Attributes={
            'VisibilityTimeout': '300',  # 5 minutes
            'ReceiveMessageWaitTimeSeconds': '20'  # Enable long polling
        }
    )
    notify_queue_url = notify_queue_response['QueueUrl']
    print("Creating the archive-retrieval notification queue " + notify_queue_url)

    # Create the chunk download queue
    chunk_queue_response = sqs.create_queue(
        QueueName=chunk_download_queue_name,
        Attributes={
            'VisibilityTimeout': str(chunk_queue_visibility_timeout),  # 5 minutes
            'ReceiveMessageWaitTimeSeconds': '0'
        }
    )
    chunk_queue_url = chunk_queue_response['QueueUrl']

    print("Creating the chunk ready notification queue " + chunk_queue_url)


   # Get the ARN for the notification queue
    notify_queue_attributes = sqs.get_queue_attributes(
        QueueUrl=notify_queue_url,
        AttributeNames=['QueueArn']
    )
    notify_queue_arn = notify_queue_attributes['Attributes']['QueueArn']

    # Set up the SNS topic policy on the notification queue
    queue_policy = {
        "Version": "2012-10-17",		 	 	 
        "Statement": [{
            "Sid": "allow-sns-messages",
            "Effect": "Allow",
            "Principal": {"AWS": "*"},
            "Action": "SQS:SendMessage",
            "Resource": notify_queue_arn,
            "Condition": {
                "ArnEquals": {
                    "aws:SourceArn": topic_arn
                }
            }
        }]
    }

    # Set the queue policy
    sqs.set_queue_attributes(
        QueueUrl=notify_queue_url,
        Attributes={
            'Policy': json.dumps(queue_policy)
        }
    )

    # Subscribe the notification queue to the SNS topic
    sns.subscribe(
        TopicArn=topic_arn,
        Protocol='sqs',
        Endpoint=notify_queue_arn
    )

    return {
        'topic_arn': topic_arn,
        'notify_queue_url': notify_queue_url,
        'chunk_queue_url': chunk_queue_url
    }


def split_and_send_chunks(archive_size, job_id,chunk_queue_url):
    ranges = []
    current = 0
    chunk_number = 0

    while current < archive_size:
        chunk_number += 1
        next_range = min(current + chunk_size - 1, archive_size - 1)
        ranges.append((current, next_range, chunk_number))
        current = next_range + 1

    # Send messages to SQS queue
    for start, end, chunk_number in ranges:
        body = {"start": start, "end": end, "job_id": job_id, "chunk_number": chunk_number}
        body = json.dumps(body)
        print("Sending SQS message for range:" + str(body))
        response = sqs.send_message(
            QueueUrl=chunk_queue_url,
            MessageBody=str(body)
        )

def GetJobOutputChunks(job_id, byterange, chunk_number):
    glacier = boto3.client('glacier')
    response = glacier.get_job_output(
        vaultName=vault_name,
        jobId=job_id,
        range=byterange,

    )

    with open(os.path.join(output_file_path,str(chunk_number)+".chunk"), 'wb') as output_file:
        output_file.write(response['body'].read())

    return response

def ReceiveArchiveReadyMessages(notify_queue_url,chunk_queue_url):

    response = sqs.receive_message(
        QueueUrl=notify_queue_url,
        AttributeNames=['All'],
        MaxNumberOfMessages=1,
        WaitTimeSeconds=20,
        MessageAttributeNames=['Message']
    )
    print("Polling archive retrieval job ready queue...")
    # Checking that there is a Messages key before proceeding. No 'Messages' key likely means the queue is empty

    if 'Messages' in response:
        print("Received a message from the archive retrieval job queue")
        jsonresponse = response
        # Loading the string into JSON and checking that ArchiveSizeInBytes key is present before continuing.
        jsonresponse=json.loads(jsonresponse['Messages'][0]['Body'])
        jsonresponse=json.loads(jsonresponse['Message'])
        if 'ArchiveSizeInBytes' in jsonresponse:
            receipt_handle = response['Messages'][0]['ReceiptHandle']    
            if jsonresponse['ArchiveSizeInBytes']:
                archive_size = jsonresponse['ArchiveSizeInBytes']

                print(f'Received message: {response}')      
                if archive_size > chunk_size:
                    split_and_send_chunks(archive_size, jsonresponse['JobId'],chunk_queue_url)

                    sqs.delete_message(
                    QueueUrl=notify_queue_url,
                    ReceiptHandle=receipt_handle)

            else:
                print("No ArchiveSizeInBytes value found in message")
                print(response)

    else:
        print('No messages available in the queue at this time.')

    time.sleep(1)

def ReceiveArchiveChunkMessages(chunk_queue_url):
    response = sqs.receive_message(
        QueueUrl=chunk_queue_url,
        AttributeNames=['All'],
        MaxNumberOfMessages=1,
        WaitTimeSeconds=0,
        MessageAttributeNames=['Message']
    )
    print("Polling archive chunk queue...")
    print(response)
    # Checking that there is a Messages key before proceeding. No 'Messages' key likely means the queue is empty
    if 'Messages' in response:
        jsonresponse = response
        # Loading the string into JSON and checking that ArchiveSizeInBytes key is present before continuing.
        jsonresponse=json.loads(jsonresponse['Messages'][0]['Body'])
        if 'job_id' in jsonresponse: #checking that there is a job id before continuing
            job_id = jsonresponse['job_id']
            byterange = "bytes="+str(jsonresponse['start']) + '-' + str(jsonresponse['end'])
            chunk_number = jsonresponse['chunk_number']
            receipt_handle = response['Messages'][0]['ReceiptHandle']
            if jsonresponse['job_id']:
                print(f'Received message: {response}')
                GetJobOutputChunks(job_id,byterange,chunk_number)
                sqs.delete_message(
                QueueUrl=chunk_queue_url,
                ReceiptHandle=receipt_handle)
    else:
        print('No messages available in the chunk queue at this time.')

def initiate_archive_retrieval(archive_id, topic_arn):
    glacier = boto3.client('glacier')

    job_parameters = {
        "Type": "archive-retrieval",
        "ArchiveId": archive_id,
        "Description": "Archive retrieval job",
        "SNSTopic": topic_arn,
        "Tier": "Bulk"  # You can change this to "Standard" or "Expedited" based on your needs
    }

    try:
        response = glacier.initiate_job(
            vaultName=vault_name,
            jobParameters=job_parameters
        )

        print("Archive retrieval job initiated:")
        print(f"Job ID: {response['jobId']}")
        print(f"Job parameters: {job_parameters}")
        print(f"Complete response: {json.dumps(response, indent=2)}")

        return response['jobId']

    except Exception as e:
        print(f"Error initiating archive retrieval job: {str(e)}")
        raise

def run_async_tasks(chunk_queue_url, workers):
    max_workers = workers  # Set the desired maximum number of concurrent tasks
    with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
        for _ in range(max_workers):
            executor.submit(ReceiveArchiveChunkMessages, chunk_queue_url)

# One time setup of the necessary queues and topics. 
queue_and_topic_atts = setup_queues_and_topic()

topic_arn = queue_and_topic_atts['topic_arn']
notify_queue_url = queue_and_topic_atts['notify_queue_url']
chunk_queue_url = queue_and_topic_atts['chunk_queue_url']

if retrieve_archive:
    print("Retrieving the defined archive... The topic arn we will notify when recalling the archive is: "+topic_arn)
    job_id = initiate_archive_retrieval(archive_id, topic_arn)
else:
    print("Retrieve archive is false, polling queues and downloading only.")

while True:
   ReceiveArchiveReadyMessages(notify_queue_url,chunk_queue_url)
   run_async_tasks(chunk_queue_url,workers)
```

## 스크립트 사용
<a name="downloading-large-archive-python-usage"></a>

이 스크립트를 사용하려면 다음 단계를 따르세요.

1. 스크립트의 자리 표시자 값을 특정 정보로 바꿉니다.
   + *output\$1file\$1path*: 청크 파일이 저장될 디렉터리
   + *vault\$1name*: S3 Glacier 볼트의 이름
   + *notify\$1queue\$1name*: 작업 알림 대기열의 이름
   + *chunk\$1download\$1queue\$1name*: 청크 다운로드 대기열의 이름
   + *sns\$1topic\$1name*: SNS 토픽의 이름
   + 볼트가 위치한 *region*: AWS region
   + *archive\$1id*: 검색할 아카이브의 ID

1. 스크립트를 실행합니다.

   ```
   python download_large_archive.py
   ```

1. 모든 청크를 다운로드한 후 다음과 같은 명령을 사용하여 청크를 단일 파일로 결합할 수 있습니다.

   ```
   cat /path/to/chunks/*.chunk > complete_archive.file
   ```

## 중요 고려 사항
<a name="downloading-large-archive-python-considerations"></a>

이 스크립트를 사용할 때는 다음 사항에 유의해야 합니다.
+ 선택한 검색 계층에 따라 S3 Glacier에서 아카이브 검색을 완료하는 데 몇 시간이 걸릴 수 있습니다.
+ 스크립트는 무기한 실행되어 대기열을 지속적으로 폴링합니다. 특정 요구 사항에 따라 종료 조건을 추가할 수 있습니다.
+ 아카이브의 모든 청크를 저장할 디스크 공간이 충분한지 확인합니다.
+ 스크립트가 중단되면 `retrieve_archive=False`를 사용해 다시 시작하여 새 검색 작업을 시작하지 않고 청크를 계속 다운로드할 수 있습니다.
+ 네트워크 대역폭 및 시스템 리소스에 따라 *chunk\$1size* 및 *workers* 파라미터를 조정합니다.
+ Amazon S3 검색, Amazon SNS 및 Amazon SQS 사용량에는 표준 AWS 요금이 적용됩니다.

# REST API를 사용하여 아카이브 다운로드
<a name="downloading-an-archive-using-rest"></a>

**REST API를 사용하여 아카이브 다운로드**

아카이브를 다운로드하는 작업은 2단계 프로세스로 구성됩니다.

1. `archive-retrieval` 유형의 작업을 시작합니다. 자세한 내용은 [작업 시작(POST jobs)](api-initiate-job-post.md) 단원을 참조하십시오.

1. 작업이 완료된 후 아카이브 데이터를 다운로드합니다. 자세한 내용은 [작업 출력 가져오기(GET output)](api-job-output-get.md) 단원을 참조하십시오.

# 를 사용하여 Amazon Glacier에서 아카이브 다운로드 AWS CLI
<a name="downloading-an-archive-using-cli"></a>

 AWS Command Line Interface ()를 사용하여 Amazon Glacier(Amazon Glacier)에서 아카이브를 다운로드할 수 있습니다AWS CLI.

**Topics**
+ [(사전 조건) 설정 AWS CLI](#Creating-Vaults-CLI-Setup)
+ [예:를 사용하여 아카이브 다운로드 AWS CLI](#Downloading-Archives-CLI-Implementation)

## (사전 조건) 설정 AWS CLI
<a name="Creating-Vaults-CLI-Setup"></a>

1.  AWS CLI를 다운로드하고 구성합니다. 관련 지침은 *AWS Command Line Interface 사용 설명서*에서 다음 토픽을 참조하세요.

    [설치 AWS Command Line Interface](https://docs.aws.amazon.com/cli/latest/userguide/installing.html) 

   [구성 AWS Command Line Interface](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html)

1. 명령 프롬프트에 다음 명령을 입력하여 AWS CLI 설정을 확인합니다. 이러한 명령은 명시적으로 자격 증명을 제공하지 않으므로 기본 프로파일의 자격 증명이 사용됩니다.
   + help 명령을 사용해 보십시오.

     ```
     aws help
     ```
   + 구성된 계정의 Amazon Glacier 볼트 목록을 가져오려면 `list-vaults` 명령을 사용합니다. *123456789012*을 AWS 계정 ID로 바꿉니다.

     ```
     aws glacier list-vaults --account-id 123456789012
     ```
   + 에 대한 현재 구성 데이터를 보려면 `aws configure list` 명령을 AWS CLI사용합니다.

     ```
     aws configure list
     ```

## 예:를 사용하여 아카이브 다운로드 AWS CLI
<a name="Downloading-Archives-CLI-Implementation"></a>
**참고**  
아카이브를 다운로드하려면 반드시 아카이브 ID를 알아야 합니다. 1\$14단계를 따라 아카이브 ID를 검색합니다. 다운로드하려는 아카이브 ID를 이미 알고 있는 경우 5단계로 건너뛰세요.

1. `initiate-job` 명령을 사용하여 인벤토리 검색 작업을 시작합니다. 인벤토리 보고서에는 사용자의 아카이브 ID가 나열됩니다.

   ```
   aws glacier initiate-job --vault-name awsexamplevault --account-id 111122223333 --job-parameters="{\"Type\":\"inventory-retrieval\"}"
   ```

    예상 결과:

   ```
   {
       "location": "/111122223333/vaults/awsexamplevault/jobs/*** jobid ***", 
       "jobId": "*** jobid ***"
   }
   ```

1. `describe-job` 명령을 사용하여 이전 `` 작업의 명령의 상태를 확인합니다.

   ```
   aws glacier describe-job --vault-name awsexamplevault --account-id 111122223333 --job-id *** jobid ***
   ```

    예상 결과:

   ```
   {
       "InventoryRetrievalParameters": {
           "Format": "JSON"
       }, 
       "VaultARN": "*** vault arn ***", 
       "Completed": false, 
       "JobId": "*** jobid ***", 
       "Action": "InventoryRetrieval", 
       "CreationDate": "*** job creation date ***", 
       "StatusCode": "InProgress"
   }
   ```

1.  작업이 완료될 때까지 기다립니다.

   작업 출력을 다운로드할 수 있을 때까지 기다려야 합니다. 볼트에서 알림 구성을 설정하거나 작업을 시작할 때 Amazon Simple Notification Service(Amazon SNS) 토픽을 지정했다면 Amazon Glacier가 작업 완료 후 해당 토픽에 메시지를 보냅니다.

   볼트의 특정 이벤트에 대해 알림 구성을 설정할 수 있습니다. 자세한 내용은 [Amazon Glacier의 볼트 알림 구성](configuring-notifications.md) 단원을 참조하십시오. Amazon Glacier는 특정 이벤트가 발생할 때마다 지정된 SNS 토픽에 메시지를 보냅니다.

1. 완료되면 `get-job-output` 명령을 사용하여 검색 작업을 `output.json` 파일로 다운로드합니다. 이 파일에는 사용자의 아카이브 ID가 포함될 것입니다.

   ```
   aws glacier get-job-output --vault-name awsexamplevault --account-id 111122223333 --job-id *** jobid *** output.json
   ```

   이 명령은 다음 필드가 있는 파일을 생성합니다.

   ```
   {
   "VaultARN":"arn:aws:glacier:region:111122223333:vaults/awsexamplevault",
   "InventoryDate":"*** job completion date ***",
   "ArchiveList":[
   {"ArchiveId":"*** archiveid ***",
   "ArchiveDescription":*** archive description (if set) ***,
   "CreationDate":"*** archive creation date ***",
   "Size":"*** archive size (in bytes) ***",
   "SHA256TreeHash":"*** archive hash ***"
   }
   {"ArchiveId":
   ...
   ]}
   ```

1. `initiate-job` 명령을 사용하여 볼트에서 각 아카이브를 검색하는 프로세스를 시작합니다. 아래 `archive-retrieval`과 같이 작업 파라미터를 지정해야 합니다.

   ```
   aws glacier initiate-job --vault-name awsexamplevault --account-id 111122223333 --job-parameters="{\"Type\":\"archive-retrieval\",\"ArchiveId\":\"*** archiveId ***\"}"
   ```

1. `archive-retrieval` 작업이 완료될 때까지 기다립니다. `describe-job` 명령을 사용하여 이전 명령의 상태를 확인합니다.

   ```
   aws glacier describe-job --vault-name awsexamplevault --account-id 111122223333 --job-id *** jobid ***
   ```

1. 위 작업이 완료되면 `get-job-output` 명령을 사용하여 아카이브를 다운로드합니다.

   ```
   aws glacier get-job-output --vault-name awsexamplevault --account-id 111122223333 --job-id *** jobid *** output_file_name
   ```