

 **此頁面僅適用於使用 Vaults 和 2012 年原始 REST API 的 Amazon Glacier 服務的現有客戶。**

如果您要尋找封存儲存解決方案，建議您在 Amazon Glacier Instant Retrieval、S3 Glacier Flexible Retrieval 和 S3 Glacier Deep Archive 中使用 Amazon Glacier 儲存類別。 Amazon S3 若要進一步了解這些儲存選項，請參閱 [Amazon Glacier 儲存類別](https://aws.amazon.com/s3/storage-classes/glacier/)。

Amazon Glacier （原始獨立保存庫型服務） 不再接受新客戶。Amazon Glacier 是一項獨立服務，具有自己的 APIs，可將資料存放在保存庫中，並與 Amazon S3 和 Amazon S3 Glacier 儲存類別不同。您現有的資料將在 Amazon Glacier 中無限期保持安全且可存取。不需要遷移。對於低成本、長期的封存儲存， AWS 建議使用 [Amazon S3 Glacier 儲存類別](https://aws.amazon.com/s3/storage-classes/glacier/)，透過 S3 儲存貯體型 APIs、完整 AWS 區域 可用性、降低成本 AWS 和服務整合，提供卓越的客戶體驗。如果您想要增強功能，請考慮使用我們的解決方案指南，將資料從 Amazon S3 Glacier 保存庫傳輸至 Amazon S3 Glacier 儲存類別，以遷移至 Amazon S3 Glacier 儲存類別。 [AWS Amazon Glacier Amazon S3 ](https://aws.amazon.com/solutions/guidance/data-transfer-from-amazon-s3-glacier-vaults-to-amazon-s3/)

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 在 Amazon Glacier 中使用封存
<a name="working-with-archives"></a>

封存是存放在保存庫中的任何物件 (如相片、影片或文件)。它是 Amazon Glacier (Amazon Glacier) 中儲存的基本單位。每個封存都有唯一的 ID 以及選擇性說明。當您上傳封存時，Amazon Glacier 會傳回包含封存 ID 的回應。此封存 ID 在存放封存 AWS 的區域中是唯一的。以下是封存 ID 範例。

```
TJgHcrOSfAkV6hdPqOATYfp_0ZaxL1pIBOc02iZ0gDPMr2ig-nhwd_PafstsdIf6HSrjHnP-3p6LCJClYytFT_CBhT9CwNxbRaM5MetS3I-GqwxI3Y8QtgbJbhEQPs0mJ3KExample
```

 封存 ID 長度為 138 位元組。當您上傳封存，可以提供可選的說明。您可以使用其 ID 而不是其說明來擷取封存。

 

**重要**  
Amazon Glacier 提供管理主控台。您可以使用主控台來建立及刪除保存庫。不過，與 Amazon Glacier 的所有其他互動都需要您使用 AWS Command Line Interface (CLI) 或寫入程式碼。例如，若要上傳資料，例如相片、影片和其他文件，您必須使用 AWS CLI 或編寫程式碼來提出請求，直接使用 REST API 或使用 Amazon SDKs。如需搭配 使用 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/)。

**Topics**
+ [在 Amazon Glacier 中封存操作](#archive-operations-quick-intro)
+ [維護用戶端封存中繼資料](#client-side-key-map-concept)
+ [在 Amazon Glacier 中上傳封存](uploading-an-archive.md)
+ [在 Amazon Glacier 中下載封存](downloading-an-archive.md)
+ [在 Amazon Glacier 中刪除封存](deleting-an-archive.md)

## 在 Amazon Glacier 中封存操作
<a name="archive-operations-quick-intro"></a>

Amazon Glacier 支援下列基本封存操作：上傳、下載和刪除。下載封存是一種非同步操作。

### 在 Amazon Glacier 中上傳封存
<a name="uploading-an-archive-quick-intro"></a>

您可以透過單一操作上傳封存，也可以分段上傳封存。您用來上傳部分封存的 API 呼叫稱為分段上傳。如需詳細資訊，請參閱[在 Amazon Glacier 中上傳封存](uploading-an-archive.md)。

 

**重要**  
Amazon Glacier 提供管理主控台。您可以使用主控台來建立及刪除保存庫。不過，與 Amazon Glacier 的所有其他互動都需要您使用 AWS Command Line Interface (CLI) 或寫入程式碼。例如，若要上傳資料，例如相片、影片和其他文件，您必須使用 AWS CLI 或編寫程式碼來提出請求，直接使用 REST API 或使用 Amazon SDKs。如需搭配 使用 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/)。

### 在 Amazon Glacier 中尋找封存 ID
<a name="finding-an-archive-id-quick-intro"></a>

您可以透過為包含封存的保存庫下載保存庫庫存來取得封存 ID。如需下載保存庫庫存的詳細資訊，請參閱[在 Amazon Glacier 中下載保存庫庫存](vault-inventory.md)。

### 在 Amazon Glacier 中下載封存
<a name="downloading-an-archive-quick-intro"></a>

下載封存是一種非同步操作。您必須先啟動任務來下載特定的封存。收到任務請求後，Amazon Glacier 會準備您的封存以供下載。任務完成後，下載封存資料。由於任務的非同步性質，您可以請求 Amazon Glacier 在任務完成時傳送通知至 Amazon Simple Notification Service (Amazon SNS) 主題。您可以為每個個別工作請求指定一個 SNS 主題，或者設定您的保存庫在特定事件發生時傳送通知。如需下載封存的詳細資訊，請參閱 [在 Amazon Glacier 中下載封存](downloading-an-archive.md)。

### 在 Amazon Glacier 中刪除封存
<a name="deleting-an-archive-quick-intro"></a>

Amazon Glacier 提供 API 呼叫，可讓您一次刪除一個封存。如需詳細資訊，請參閱[在 Amazon Glacier 中刪除封存](deleting-an-archive.md)。

### 在 Amazon Glacier 中更新封存
<a name="updating-an-archive-quick-intro"></a>

在您上傳封存後，您不能更新內容或其說明。您可以更新封存內容或其說明的唯一方法是刪除封存並上傳另一個封存。請注意，每次上傳封存時，Amazon Glacier 都會傳回唯一的封存 ID。

## 維護用戶端封存中繼資料
<a name="client-side-key-map-concept"></a>

除了選用的封存描述之外，Amazon Glacier 不支援封存的任何其他中繼資料。當您上傳封存時，Amazon Glacier 會指派 ID，這是不透明的字元序列，您無法從中推斷封存的任何意義。您可以在用戶端維護封存的中繼資料。中繼資料可以包括封存名稱和有關封存的其他有意義的資訊。

**注意**  
如果您是 Amazon Simple Storage Service (Amazon S3) 的客戶，您就會知道，當物件上傳到儲存貯體時，您可以將物件指定為物件金鑰，例如 `MyDocument.txt` 或 `SomePhoto.jpg`。在 Amazon Glacier 中，您無法將物件金鑰指派給您上傳的封存。

如果您維護用戶端封存中繼資料，請注意，Amazon Glacier 會維護保存庫庫存，其中包含封存 IDs和您在封存上傳期間提供的任何說明。您可能偶爾會下載保存庫庫存，以協調為封存中繼資料維護的用戶端資料庫中的任何問題。不過，Amazon Glacier 大約每天會取得保存庫庫存。當您請求保存庫庫存時，Amazon Glacier 會傳回其所準備的最後一個庫存，是某個時間點快照。

# 在 Amazon Glacier 中上傳封存
<a name="uploading-an-archive"></a>

Amazon Glacier (Amazon Glacier) 提供管理主控台，可用來建立和刪除保存庫。不過，您無法使用 管理主控台將封存上傳至 Amazon Glacier。若要上傳資料，例如相片、影片和其他文件，您必須直接使用 REST API AWS CLI 或使用 Amazon SDKs，使用 或編寫程式碼來提出請求。

如需有關搭配 使用 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/)。下列**上傳**主題說明如何使用適用於 Java 的 Amazon 開發套件、適用於 .NET 的 Amazon 開發套件和 REST API 將封存上傳至 Amazon Glacier。

**Topics**
+ [將封存上傳至 Amazon Glacier 的選項](#uploading-an-archive-overview)
+ [在單一操作中上傳封存](uploading-archive-single-operation.md)
+ [上傳分段中的大型封存 (分段上傳)](uploading-archive-mpu.md)

## 將封存上傳至 Amazon Glacier 的選項
<a name="uploading-an-archive-overview"></a>

視您上傳的資料大小而定，Amazon Glacier 會提供下列選項：
+ **在單一作業中上傳封存**：在單一作業中，您可以上傳大小為 1 位元組到最大 4 GB 的封存。不過，我們鼓勵 Amazon Glacier 客戶使用分段上傳來上傳大於 100 MB 的封存。如需詳細資訊，請參閱[在單一操作中上傳封存](uploading-archive-single-operation.md)。
+ **上傳部分封存** - 使用分段上傳 API，您可以上傳大型封存，最高可達 40,000 GB (10,000\$1 4 GB)。

  分段上傳 API 呼叫是專為改善較大型封存上傳體驗所設計。您可以分段上傳封存。這些封存部分可個別、依任何順序以及同時上傳。如果某個部分上傳失敗，您只需要再次上傳該部分，而不是整個封存。您可以為大小介於 1 位元組到 40,000 GB 之間的封存使用分段上傳。如需詳細資訊，請參閱[上傳分段中的大型封存 (分段上傳)](uploading-archive-mpu.md)。

**重要**  
Amazon Glacier 保存庫庫存每天只會更新一次。當上傳封存時，您將不會立即看到新增到文件庫的新存檔 (在主控台中或在下載的文件庫清查清單中)，直到文件庫清查已更新。

### 使用 AWS Snowball Edge 服務
<a name="using-import-export-service-for-glacier"></a>

AWS Snowball Edge 加速 AWS 使用 Amazon 擁有的裝置進出大量資料，繞過網際網路。如需詳細資訊，請參閱 [AWS Snowball Edge](https://aws.amazon.com/snowball) 的詳細資訊頁面。

若要將現有資料上傳至 Amazon Glacier (Amazon Glacier)，您可以考慮使用其中一種 AWS Snowball Edge 裝置類型將資料匯入 Amazon S3，然後使用生命週期規則將其移至 Amazon Glacier 儲存類別以進行封存。當您將 Amazon S3 物件轉換為 Amazon Glacier 儲存類別時，Amazon S3 會在內部使用 Amazon Glacier 以較低成本提供耐久儲存。雖然物件存放在 Amazon Glacier 中，他們會保有您在 Amazon S3 中管理的 Amazon S3 物件，且您無法透過 Amazon Glacier 直接存取。

如需 Amazon S3 生命週期組態和將物件轉換為 Amazon Glacier 儲存類別的詳細資訊，請參閱《*Amazon Simple Storage Service 使用者指南*》中的[物件生命週期管理和](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lifecycle-mgmt.html)[轉換物件](https://docs.aws.amazon.com/AmazonS3/latest/userguide/lifecycle-transition-general-considerations.html)。

# 在單一操作中上傳封存
<a name="uploading-archive-single-operation"></a>

如 [在 Amazon Glacier 中上傳封存](uploading-an-archive.md) 中所述，您可以在單一操作中上傳較小的封存。不過，我們鼓勵 Amazon Glacier (Amazon Glacier) 客戶使用分段上傳上傳大於 100 MB 的封存。

**Topics**
+ [使用 在單一操作中上傳封存 AWS Command Line Interface](uploading-an-archive-single-op-using-cli.md)
+ [使用 在單一操作中上傳封存 適用於 Java 的 AWS SDK](uploading-an-archive-single-op-using-java.md)
+ [在 Amazon Glacier 中使用 在單一操作 適用於 .NET 的 AWS SDK 中上傳封存](uploading-an-archive-single-op-using-dotnet.md)
+ [使用 REST API 在單一操作中上傳封存](uploading-an-archive-single-op-using-rest.md)

# 使用 在單一操作中上傳封存 AWS Command Line Interface
<a name="uploading-an-archive-single-op-using-cli"></a>

您可以使用 AWS Command Line Interface () 在 Amazon Glacier (Amazon Glacier) 中上傳封存AWS CLI。

**Topics**
+ [（先決條件） 設定 AWS CLI](#Creating-Vaults-CLI-Setup)
+ [範例：使用 上傳封存 AWS CLI](#Uploading-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 設定。這些命令不會明確提供登入資料，因此會使用預設描述檔的登入資料。
   + 嘗試使用幫助命令。

     ```
     aws help
     ```
   + 若要取得已設定帳戶上的 Amazon Glacier 保存庫清單，請使用 `list-vaults`命令。將 *123456789012* 取代為您的 AWS 帳戶 ID。

     ```
     aws glacier list-vaults --account-id 123456789012
     ```
   + 若要查看 目前的組態資料 AWS CLI，請使用 `aws configure list`命令。

     ```
     aws configure list
     ```

## 範例：使用 上傳封存 AWS CLI
<a name="Uploading-Archives-CLI-Implementation"></a>

若要上傳封存，您必須建立保存庫。如需有關建立保存庫的詳細資訊，請參閱[在 Amazon Glacier 中建立保存庫](creating-vaults.md)。

1. 使用 `upload-archive` 命令將封存新增至現有保存庫。在下面的範例中替換 `vault name` 和 `account ID`。對於 `body` 參數，指定您要上傳之檔案的路徑。

   ```
   aws glacier upload-archive --vault-name awsexamplevault --account-id 123456789012 --body archive.zip
   ```

1.  預期的輸出結果：

   ```
   {
       "archiveId": "kKB7ymWJVpPSwhGP6ycSOAekp9ZYe_--zM_mw6k76ZFGEIWQX-ybtRDvc2VkPSDtfKmQrj0IRQLSGsNuDp-AJVlu2ccmDSyDUmZwKbwbpAdGATGDiB3hHO0bjbGehXTcApVud_wyDw",
       "checksum": "969fb39823836d81f0cc028195fcdbcbbe76cdde932d4646fa7de5f21e18aa67",
       "location": "/123456789012/vaults/awsexamplevault/archives/kKB7ymWJVpPSwhGP6ycSOAekp9ZYe_--zM_mw6k76ZFGEIWQX-ybtRDvc2VkPSDtfKmQrj0IRQLSGsNuDp-AJVlu2ccmDSyDUmZwKbwbpAdGATGDiB3hHO0bjbGehXTcApVud_wyDw"
   }
   ```

   完成時，命令將輸出 Amazon Glacier 中的封存 ID、檢查總和和和位置。如需有關 upload-archive 命令的詳細資訊，請參閱《AWS CLI 命令參考》**中的 [upload-archive](https://docs.aws.amazon.com/cli/latest/reference/glacier/upload-archive.html)。

# 使用 在單一操作中上傳封存 適用於 Java 的 AWS SDK
<a name="uploading-an-archive-single-op-using-java"></a>

適用於 Java 的 Amazon 開發套件提供的[高階和低階 API](using-aws-sdk.md) 都提供了上傳封存的方法。

**Topics**
+ [使用 的高階 API 上傳封存 適用於 Java 的 AWS SDK](#uploading-an-archive-single-op-high-level-using-java)
+ [使用 的低階 API 在單一操作中上傳封存 適用於 Java 的 AWS SDK](#uploading-an-archive-single-op-low-level-using-java)

## 使用 的高階 API 上傳封存 適用於 Java 的 AWS SDK
<a name="uploading-an-archive-single-op-high-level-using-java"></a>

高階 API 的 `ArchiveTransferManager` 類別提供 `upload` 方法，可以使用該方法將存檔上傳到文件庫。

 

**注意**  
您可以使用 `upload` 方法上傳小型或大型封存。根據您要上傳的封存大小，此方法會判斷在單一操作上傳，或使用分段上傳 API 將封存分成部分上傳。

### 範例：使用 的高階 API 上傳封存 適用於 Java 的 AWS SDK
<a name="upload-archive-high-level-java-example"></a>

以下 Java 程式碼範例將封存上傳到美國西部 (奧勒岡) 區域 (`us-west-2`) 中的保存庫 (`examplevault`)。如需支援 AWS 的區域和端點清單，請參閱 [存取 Amazon Glacier](amazon-glacier-accessing.md)。

如需執行此範例的逐步說明，請參閱 [使用 Eclipse 執行 Amazon Glacier 的 Java 範例](using-aws-sdk-for-java.md#setting-up-and-testing-sdk-java)。您需要更新程式碼，如所示的要上傳的保存庫名稱和要上傳的檔案名稱。

**Example**  

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

import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.glacier.AmazonGlacierClient;
import com.amazonaws.services.glacier.transfer.ArchiveTransferManager;
import com.amazonaws.services.glacier.transfer.UploadResult;


public class ArchiveUploadHighLevel {
    public static String vaultName = "*** provide vault name ***";
    public static String archiveToUpload = "*** provide name of file to upload ***";
    
    public static AmazonGlacierClient client;
    
    public static void main(String[] args) throws IOException {
        
        
    	ProfileCredentialsProvider credentials = new ProfileCredentialsProvider();
    	
        client = new AmazonGlacierClient(credentials);
        client.setEndpoint("https://glacier.us-west-2.amazonaws.com/");

        try {
            ArchiveTransferManager atm = new ArchiveTransferManager(client, credentials);
            
            UploadResult result = atm.upload(vaultName, "my archive " + (new Date()), new File(archiveToUpload));
            System.out.println("Archive ID: " + result.getArchiveId());
            
        } catch (Exception e)
        {
            System.err.println(e);
        }
    }
}
```

## 使用 的低階 API 在單一操作中上傳封存 適用於 Java 的 AWS SDK
<a name="uploading-an-archive-single-op-low-level-using-java"></a>

低階 API 提供所有封存操作的方法。以下是使用 適用於 Java 的 AWS SDK上傳封存的步驟。

 

1. 建立 `AmazonGlacierClient` 類別的執行個體 (用戶端)。

   您需要指定要上傳封存 AWS 的區域。您使用此用戶端執行的所有操作都會套用到該 AWS 區域。

1. 您可以透過建立 `UploadArchiveRequest` 類別的執行個體來提供請求資訊。

   除了要上傳的資料外，還需要提供承載的檢查總和 (SHA-256 樹狀雜湊)、保存庫名稱、資料的內容長度和帳戶 ID。

   如果您不提供帳戶 ID，則會使用與您提供來簽署請求之登入資料關聯的帳戶 ID。如需詳細資訊，請參閱[適用於 Java 的 AWS SDK 搭配 Amazon Glacier 使用](using-aws-sdk-for-java.md)。

1. 以參數形式提供請求物件，以便執行 `uploadArchive` 方法。

   為了回應，Amazon Glacier (Amazon Glacier) 會傳回新上傳封存的封存 ID。

下列 Java 程式碼片段描述前述步驟。

```
AmazonGlacierClient client;

UploadArchiveRequest request = new UploadArchiveRequest()
    .withVaultName("*** provide vault name ***")
    .withChecksum(checksum)
    .withBody(new ByteArrayInputStream(body))
    .withContentLength((long)body.length);

UploadArchiveResult uploadArchiveResult = client.uploadArchive(request);

System.out.println("Location (includes ArchiveID): " + uploadArchiveResult.getLocation());
```

### 範例：使用 的低階 API 在單一操作中上傳封存 適用於 Java 的 AWS SDK
<a name="uploding-single-archive-using-java-example"></a>

下列 Java 程式碼範例使用 適用於 Java 的 AWS SDK 將封存上傳至保存庫 (`examplevault`)。如需執行此範例的逐步說明，請參閱 [使用 Eclipse 執行 Amazon Glacier 的 Java 範例](using-aws-sdk-for-java.md#setting-up-and-testing-sdk-java)。您需要更新程式碼，如所示的要上傳的保存庫名稱和要上傳的檔案名稱。

```
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.glacier.AmazonGlacierClient;
import com.amazonaws.services.glacier.TreeHashGenerator;
import com.amazonaws.services.glacier.model.UploadArchiveRequest;
import com.amazonaws.services.glacier.model.UploadArchiveResult;
public class ArchiveUploadLowLevel {

    public static String vaultName = "*** provide vault name ****";
    public static String archiveFilePath = "*** provide to file upload ****";
    public static AmazonGlacierClient client;
    
    public static void main(String[] args) throws IOException {
    	
    	ProfileCredentialsProvider credentials = new ProfileCredentialsProvider();

        client = new AmazonGlacierClient(credentials);
        client.setEndpoint("https://glacier.us-east-1.amazonaws.com/");

        try {
            // First open file and read.
            File file = new File(archiveFilePath);
            InputStream is = new FileInputStream(file); 
            byte[] body = new byte[(int) file.length()];
            is.read(body);
                                    
            // Send request.
            UploadArchiveRequest request = new UploadArchiveRequest()
                .withVaultName(vaultName)
                .withChecksum(TreeHashGenerator.calculateTreeHash(new File(archiveFilePath))) 
                .withBody(new ByteArrayInputStream(body))
                .withContentLength((long)body.length);
            
            UploadArchiveResult uploadArchiveResult = client.uploadArchive(request);
            
            System.out.println("ArchiveID: " + uploadArchiveResult.getArchiveId());
            
        } catch (Exception e)
        {
            System.err.println("Archive not uploaded.");
            System.err.println(e);
        }
    }
}
```

# 在 Amazon Glacier 中使用 在單一操作 適用於 .NET 的 AWS SDK 中上傳封存
<a name="uploading-an-archive-single-op-using-dotnet"></a>

適用於 .NET 的 Amazon 開發套件提供的[高階和低階 API](using-aws-sdk.md) 都提供了在單一作業中上傳封存的方法。

**Topics**
+ [使用 的高階 API 上傳封存 適用於 .NET 的 AWS SDK](#uploading-an-archive-single-op-highlevel-using-dotnet)
+ [使用 的低階 API 在單一操作中上傳封存 適用於 .NET 的 AWS SDK](#uploading-an-archive-single-op-lowlevel-using-dotnet)

## 使用 的高階 API 上傳封存 適用於 .NET 的 AWS SDK
<a name="uploading-an-archive-single-op-highlevel-using-dotnet"></a>

高階 API 的 `ArchiveTransferManager` 類別提供 `Upload` 方法，您可以使用該方法將存檔上傳到文件庫。

**注意**  
您可以使用 `Upload` 方法上傳小型或大型檔案。根據您要上傳的檔案大小，此方法會判斷在單一操作上傳，或使用分段上傳 API 以將檔案分段上傳。

### 範例：使用 的高階 API 上傳封存 適用於 .NET 的 AWS SDK
<a name="upload-archive-highlevel-any-size-dotnet"></a>

以下 C\$1 程式碼範例將封存上傳到美國西部 (奧勒岡) 區域中的保存庫 (`examplevault`)。

如需執行此範例的逐步說明，請參閱 [執行程式碼範例](using-aws-sdk-for-dot-net.md#setting-up-and-testing-sdk-dotnet)。您必須如所示，使用要上傳的檔案名稱更新程式碼。

**Example**  

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

namespace glacier.amazon.com.rproxy.govskope.us.docsamples
{
  class ArchiveUploadHighLevel
  {
    static string vaultName = "examplevault"; 
    static string archiveToUpload = "*** Provide file name (with full path) to upload ***";

    public static void Main(string[] args)
    {
       try
      {
         var manager = new ArchiveTransferManager(Amazon.RegionEndpoint.USWest2);
         // Upload an archive.
         string archiveId = manager.Upload(vaultName, "upload archive test", archiveToUpload).ArchiveId;
         Console.WriteLine("Archive ID: (Copy and save this ID for use in other examples.) : {0}", archiveId);
         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();
    }
  }
}
```

## 使用 的低階 API 在單一操作中上傳封存 適用於 .NET 的 AWS SDK
<a name="uploading-an-archive-single-op-lowlevel-using-dotnet"></a>

低階 API 提供所有封存操作的方法。以下是使用 適用於 .NET 的 AWS SDK上傳封存的步驟。

 

1. 建立 `AmazonGlacierClient` 類別的執行個體 (用戶端)。

   您需要指定要上傳封存 AWS 的區域。您使用此用戶端執行的所有操作都會套用到該 AWS 區域。

1. 您可以透過建立 `UploadArchiveRequest` 類別的執行個體來提供請求資訊。

   除了要上傳的資料外，還需要提供承載的檢查總和 (SHA-256 樹狀雜湊)、保存庫名稱和帳戶 ID。

   如果您不提供帳戶 ID，則會使用與您提供來簽署請求之登入資料關聯的帳戶 ID。如需詳細資訊，請參閱[適用於 .NET 的 AWS SDK 搭配 Amazon Glacier 使用](using-aws-sdk-for-dot-net.md)。

1. 以參數形式提供請求物件，以便執行 `UploadArchive` 方法。

   為了回應，Amazon Glacier 會傳回新上傳封存的封存 ID。

### 範例：使用 的低階 API 在單一操作中上傳封存 適用於 .NET 的 AWS SDK
<a name="upload-archive-single-op-lowlevel-dotnet"></a>

下列 C\$1 程式碼範例描述前述步驟。此範例使用 適用於 .NET 的 AWS SDK 將封存上傳至保存庫 (`examplevault`)。

**注意**  
如需有關底層 REST API 在單一請求中上傳封存的詳細資訊，請參閱 [上傳封存 (POST 封存)](api-archive-post.md)。

如需執行此範例的逐步說明，請參閱 [執行程式碼範例](using-aws-sdk-for-dot-net.md#setting-up-and-testing-sdk-dotnet)。您必須如所示，使用要上傳的檔案名稱更新程式碼。

**Example**  

```
using System;
using System.IO;
using Amazon.Glacier;
using Amazon.Glacier.Model;
using Amazon.Runtime;

namespace glacier.amazon.com.rproxy.govskope.us.docsamples
{
  class ArchiveUploadSingleOpLowLevel
  {
    static string vaultName       = "examplevault";
    static string archiveToUpload = "*** Provide file name (with full path) to upload ***";

    public static void Main(string[] args)
    {
      AmazonGlacierClient client;
      try
      {
         using (client = new AmazonGlacierClient(Amazon.RegionEndpoint.USWest2))
        {
          Console.WriteLine("Uploading an archive.");
          string archiveId = UploadAnArchive(client);
          Console.WriteLine("Archive ID: {0}", archiveId);
        }
      }
      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 string UploadAnArchive(AmazonGlacierClient client)
    {
      using (FileStream fileStream = new FileStream(archiveToUpload, FileMode.Open, FileAccess.Read))
      {
        string treeHash = TreeHashGenerator.CalculateTreeHash(fileStream);
        UploadArchiveRequest request = new UploadArchiveRequest()
        {
          VaultName = vaultName,
          Body = fileStream,
          Checksum = treeHash
        };
        UploadArchiveResponse response = client.UploadArchive(request);
        string archiveID = response.ArchiveId;
        return archiveID;
      }
    }
  }
}
```

# 使用 REST API 在單一操作中上傳封存
<a name="uploading-an-archive-single-op-using-rest"></a>

您可以使用上傳封存 API 呼叫以在單一操作中上傳封存。如需詳細資訊，請參閱[上傳封存 (POST 封存)](api-archive-post.md)。

# 上傳分段中的大型封存 (分段上傳)
<a name="uploading-archive-mpu"></a>

**Topics**
+ [分段上傳程序](#MPUprocess)
+ [現況](#qfacts)
+ [使用 上傳大型封存 AWS CLI](uploading-an-archive-mpu-using-cli.md)
+ [範例：使用適用於 Java 的 Amazon 開發套件，以部分形式上傳大型封存](uploading-an-archive-mpu-using-java.md)
+ [使用 上傳大型封存 適用於 .NET 的 AWS SDK](uploading-an-archive-mpu-using-dotnet.md)
+ [使用 REST API 上傳分段中的大型封存](uploading-an-archive-mpu-using-rest.md)

## 分段上傳程序
<a name="MPUprocess"></a>

如 中所述[在 Amazon Glacier 中上傳封存](uploading-an-archive.md)，我們鼓勵 Amazon Glacier (Amazon Glacier) 客戶使用分段上傳來上傳大於 100 MB (MiB) 的封存。

1. **啟動分段上傳** 

   當您傳送啟動分段上傳的請求時，Amazon Glacier 會傳回分段上傳 ID，這是分段上傳的唯一識別符。任何後續分段上傳操作中都需要此 ID。此 ID 在 Amazon Glacier 完成任務後至少 24 小時內不會過期。

   當您要求啟動分段上傳時，請指定分段大小 (以位元組為單位)。您上傳的每個分段，除了最後一個分段，都必須為這個大小。
**注意**  
您不需要了解使用分段上傳時的整體存檔大小。這表示您在開始上傳存檔時，可以在不知道存檔大小的情況下，使用分段上傳。您只需要在啟動分段上傳時，決定分段大小。

   在起始分段上傳請求時，您也可以提供選用的封存描述。

1. **分段上傳**

   對於每個分段上傳請求，您必須包含在步驟 1 取得的分段上傳 ID。在請求中，您還必須指定內容範圍 (以位元組為單位)，識別分段在最終封存中的位置。Amazon Glacier 稍後會使用內容範圍資訊，以適當的順序組合封存。由於您提供內容範圍給上傳的每個分段，它會在封存的最終組件中決定分段的位置，因此您可以任何順序上傳分段。您也可以平行上傳這些分段。如果您使用和之前上傳分段相同的內容範圍上傳新的分段，將會覆寫之前上傳的分段。

1. **完成 (或停止) 分段上傳**

   上傳所有封存分段之後，您可以完整的操作。同樣地，您必須在請求中指定上傳 ID。Amazon Glacier 會根據您提供的內容範圍，以遞增順序串連組件來建立封存。Amazon Glacier 對完整分段上傳請求的回應包含新建立封存的封存 ID。如果您在啟動分段上傳請求中提供選用的封存描述，Amazon Glacier 會將其與組合的封存建立關聯。在您成功完成分段上傳後，您無法參照分段上傳 ID。這表示您無法存取與該分段上傳 ID 關聯的分段。

   如果停止分段上傳，您即無法使用該分段上傳 ID 上傳更多的分段。與已停止分段上傳關聯之任何部分耗用的所有儲存體都會釋出。如有任何部分上傳正在進行，則會在停止後仍會成功或失敗。

### 其他分段上傳操作
<a name="additional-mpu-operations"></a>

Amazon Glacier (Amazon Glacier) 提供下列額外的分段上傳 API 呼叫。

 
+ **列出部分**：使用此作業時，您可以列出特定分段上傳的部分。它會傳回有關已針對分段上傳上傳之分段的資訊。對於每個清單組件請求，Amazon Glacier 會傳回最多 1，000 個組件的資訊。如果有更多分段要針對分段上傳列出，結果會分頁並在繼續列出的回應中傳回標記。您需要傳送額外的請求，以擷取後續分段。請注意，傳回的組件清單不包含尚未完成之上傳的組件。
+ **列出分段上傳**：使用此作業，您即可取得進行中之分段上傳的清單。進行中的分段上傳是您已啟動但尚未完成或已停止的上傳。對於每個列出分段上傳請求，Amazon Glacier 會傳回最多 1,000 個分段上傳。如果有更多分段要列出，則結果會分頁並在繼續列出的回應中傳回標記。您需要傳送額外的請求，以擷取剩餘的分段上傳。

## 現況
<a name="qfacts"></a>

下表提供分段上傳核心規格。


| 項目 | 規格 | 
| --- | --- | 
| 最大封存大小 | 10,000 x 4 gibibytes (GiB)  | 
| 每次上傳的組件數目上限 | 10,000 | 
| 組件大小 | 1 MiB 至 4 GiB，最後一個部分可以是 < 1 MiB。您可以位元組指定大小值。 部分大小必須是 1 MiB (1024 kibibytes [KiB]) 乘以 2 的乘方。例如，`1048576` (1 MiB)、`2097152` (2 MiB)、`4194304` (4 MiB)、`8388608` (8 MiB)。  | 
| 列出組件要求的傳回組件數上限 | 1,000  | 
| 列出分段上傳要求所傳回的分段上傳數目上限 | 1,000  | 

# 使用 上傳大型封存 AWS CLI
<a name="uploading-an-archive-mpu-using-cli"></a>

您可以使用 AWS Command Line Interface () 在 Amazon Glacier (Amazon Glacier) 中上傳封存AWS CLI。為了改善大型封存的上傳體驗，Amazon Glacier 提供多種 API 操作來支援分段上傳。透過使用這些 API 作業，您能夠以部分形式上傳封存。這些封存部分可個別、依任何順序以及同時上傳。如果某個部分上傳失敗，您需要再次上傳該部分，而不是整個封存。您可以為大小介於 1 位元組到 40,000 GiB 之間的封存使用分段上傳。

如需 Amazon Glacier 分段上傳的詳細資訊，請參閱 [上傳分段中的大型封存 (分段上傳)](uploading-archive-mpu.md)。

**Topics**
+ [（先決條件） 設定 AWS CLI](#Creating-Vaults-CLI-Setup)
+ [(先決條件) 安裝 Python](#Uploading-Archives-mpu-CLI-Install-Python)
+ [（先決條件） 建立 Amazon Glacier 保存庫](#Uploading-Archives-mpu-CLI-Create-Vault)
+ [範例：使用 分段上傳大型封存 AWS CLI](#Uploading-Archives-mpu-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 設定。這些命令不會明確提供登入資料，因此會使用預設描述檔的登入資料。
   + 嘗試使用幫助命令。

     ```
     aws help
     ```
   + 若要取得已設定帳戶上的 Amazon Glacier 保存庫清單，請使用 `list-vaults`命令。將 *123456789012* 取代為您的 AWS 帳戶 ID。

     ```
     aws glacier list-vaults --account-id 123456789012
     ```
   + 若要查看 目前的組態資料 AWS CLI，請使用 `aws configure list`命令。

     ```
     aws configure list
     ```

## (先決條件) 安裝 Python
<a name="Uploading-Archives-mpu-CLI-Install-Python"></a>

若要完成分段上傳，您必須計算要上傳之封存的 SHA256 樹雜湊。這樣做與計算要上傳之檔案的 SHA256 樹雜湊不同。若要計算您要上傳之封存的 SHA256 樹雜湊，您可以使用 Java、C\$1 (使用 .NET) 或 Python。在此範例中，您將使用 Python。如需使用 Java 或 C\$1 的指示，請參閱[運算檢查總和](checksum-calculations.md)。

如需安裝 Python 的詳細資訊，請參閱《*Boto3 開發人員指南*》中的[安裝或更新 Python](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html#installation)。

## （先決條件） 建立 Amazon Glacier 保存庫
<a name="Uploading-Archives-mpu-CLI-Create-Vault"></a>

若要使用下列範例，您必須建立至少一個 Amazon Glacier 保存庫。如需有關建立保存庫的詳細資訊，請參閱[在 Amazon Glacier 中建立保存庫](creating-vaults.md)。

## 範例：使用 分段上傳大型封存 AWS CLI
<a name="Uploading-Archives-mpu-CLI-Implementation"></a>

在此範例中，您將建立檔案並使用分段上傳 API 作業，將此檔案以部分的形式上傳到 Amazon Glacier。
**重要**  
開始此程序之前，請確認您已執行所有必要步驟。若要上傳封存，您必須建立保存庫、設定 AWS CLI 並準備好使用 Java、C\$1 或 Python 來計算 SHA256 樹雜湊。

下列程序使用 `initiate-multipart-upload`、 `upload-multipart-part`和 `complete-multipart-upload` AWS CLI 命令。

如需有關這些命令之一的詳細資訊，請參閱《AWS CLI 命令參考》**中 [https://docs.aws.amazon.com/cli/latest/reference/glacier/initiate-multipart-upload.html](https://docs.aws.amazon.com/cli/latest/reference/glacier/initiate-multipart-upload.html)、[https://docs.aws.amazon.com/cli/latest/reference/glacier/upload-multipart-part.html](https://docs.aws.amazon.com/cli/latest/reference/glacier/upload-multipart-part.html) 和 [https://docs.aws.amazon.com/cli/latest/reference/glacier/complete-multipart-upload.html](https://docs.aws.amazon.com/cli/latest/reference/glacier/complete-multipart-upload.html)。

1. 使用 [https://docs.aws.amazon.com/cli/latest/reference/glacier/initiate-multipart-upload.html](https://docs.aws.amazon.com/cli/latest/reference/glacier/initiate-multipart-upload.html) 命令以建立分段上傳資源。請指定在請求中部分大小 (以位元組為單位)。您上傳的每個部分，除了最後一個部分，都將是這個大小。您不需要了解啟動上傳時的整體封存大小。但是，在完成最後一步的上傳時，您將需要每個部分的總大小 (以位元組為單位)。

   在下列命令中，將 `--vault-name` 和 `--account-ID` 參數的值替換為您自己的資訊。此命令指定您將上傳每個檔案部分大小為 1 MiB (1024 x 1024 位元組) 的封存。如有需要，請替換此 `--part-size` 參數值。

   ```
   aws glacier initiate-multipart-upload --vault-name awsexamplevault --part-size 1048576 --account-id 123456789012
   ```

   預期的輸出結果：

   ```
   {
   "location": "/123456789012/vaults/awsexamplevault/multipart-uploads/uploadId",
   "uploadId": "uploadId"
   }
   ```

   完成後，命令將輸出分段上傳資源在 Amazon Glacier 中的上傳 ID 和位置。於後續步驟中，您將會使用此上傳 ID。

1. 在此範例中，您可以使用下列命令建立 4.4 MiB 檔案，將其分割成 1 MiB 區塊，然後上傳每個區塊。若要上傳自己的檔案，您可以按照類似的程序，將資料分區並上傳每個部分。

   

**Linux 或 macOS**  
下列命令會在 Linux 或 macOS 上建立名為 `file_to_upload` 的 4.4 MiB 檔案。

   ```
   mkfile -n 9000b file_to_upload
   ```

**Windows**  
下列命令會在 Windows 上建立名為 `file_to_upload` 的 4.4 MiB 檔案。

   ```
   fsutil file createnew file_to_upload 4608000
   ```

1. 接下來，您將這個檔案分割成 1 MiB 區塊。

   ```
   split -b 1048576 file_to_upload chunk
   ```

   您現在擁有以下五個區塊。前四個是 1 MiB，最後一個大約是 400 KiB。

   ```
   chunkaa
   chunkab
   chunkac
   chunkad
   chunkae
   ```

1. 使用 [https://docs.aws.amazon.com/cli/latest/reference/glacier/upload-multipart-part.html](https://docs.aws.amazon.com/cli/latest/reference/glacier/upload-multipart-part.html) 命令以上傳部分封存。您可以依任何順序上傳封存部分。您也可以平行上傳這些部分。您可以上傳多達 10,000 個部分的分段上傳。

   在下列命令中，替換 `--vault-name`、`--account-ID` 和 `--upload-id` 參數的值。上傳 ID 必須與 `initiate-multipart-upload` 命令輸出的 ID 相符。此 `--range` 參數指定您將上傳大小為 1 MiB (1024 x 1024 位元組) 的部分。此大小必須符合您在 `initiate-multipart-upload` 命令中指定的大小。如有需要，請調整此大小值。此 `--body` 參數會指定您要上傳之部分的名稱。

   ```
   aws glacier upload-multipart-part --body chunkaa --range='bytes 0-1048575/*' --vault-name awsexamplevault --account-id 123456789012 --upload-id upload_ID
   ```

   如果成功，該命令將產生輸出，其中內含上傳部分的檢查總和。

1. 再次執行 `upload-multipart-part` 命令，以上傳分段上傳的剩餘部分。更新每個命令的 `--range` 和 `–-body` 參數值，以符合您要上傳的部分。

   ```
   aws glacier upload-multipart-part --body chunkab --range='bytes 1048576-2097151/*' --vault-name awsexamplevault --account-id 123456789012 --upload-id upload_ID
   ```

   ```
   aws glacier upload-multipart-part --body chunkac --range='bytes 2097152-3145727/*' --vault-name awsexamplevault --account-id 123456789012 --upload-id upload_ID
   ```

   ```
   aws glacier upload-multipart-part --body chunkad --range='bytes 3145728-4194303/*' --vault-name awsexamplevault --account-id 123456789012 --upload-id upload_ID
   ```

   ```
   aws glacier upload-multipart-part --body chunkae --range='bytes 4194304-4607999/*' --vault-name awsexamplevault --account-id 123456789012 --upload-id upload_ID
   ```
**注意**  
最終命令的 `--range` 參數值較小，因為上傳的最後一部分小於 1 MiB。如果成功，每個命令都會產生輸出，內含每個上傳部分的檢查總和。

1. 接下來，您將組合封存並完成上傳。您必須包含封存的總大小和 SHA256 樹雜湊。

   若要計算封存的 SHA256 樹雜湊，您可以使用 Java、C\$1 或 Python。在此範例中，您將使用 Python。如需使用 Java 或 C\$1 的指示，請參閱[運算檢查總和](checksum-calculations.md)。

   建立 Python 檔案 `checksum.py` 並插入下列程式碼。如果需要，請替換原始檔案的名稱。

   ```
   from botocore.utils import calculate_tree_hash
   					
   checksum = calculate_tree_hash(open('file_to_upload', 'rb'))
   print(checksum)
   ```

1. 執行 `checksum.py` 以計算 SHA256 樹雜湊。以下雜湊可能與輸出不相符。

   ```
   $ python3 checksum.py
   $ 3d760edb291bfc9d90d35809243de092aea4c47b308290ad12d084f69988ae0c
   ```

1. 使用 [https://docs.aws.amazon.com/cli/latest/reference/glacier/complete-multipart-upload.html](https://docs.aws.amazon.com/cli/latest/reference/glacier/complete-multipart-upload.html) 命令完成封存上傳。替換 `--vault-name`、`--account-ID`、`--upload-ID` 和 `--checksum` 參數的值。`--archive` 參數值指定封存的總大小 (以位元組為單位)。這個值必須是您上傳的個別部分之所有大小的總和。如有需要，請替換此值。

   ```
   aws glacier complete-multipart-upload --archive-size 4608000 --vault-name awsexamplevault --account-id 123456789012 --upload-id upload_ID --checksum checksum
   ```

   完成後，命令將輸出封存的 ID、檢查總和和和 Amazon Glacier 中的位置。

# 範例：使用適用於 Java 的 Amazon 開發套件，以部分形式上傳大型封存
<a name="uploading-an-archive-mpu-using-java"></a>

適用於 Java 的 Amazon 開發套件提供的[高階和低階 API](using-aws-sdk.md) 都提供了上傳大型封存的方法 (請參閱 [在 Amazon Glacier 中上傳封存](uploading-an-archive.md))。

 
+ 高階的 API 提供了一種可用來上傳任何大小的封存的方法。根據您上傳的檔案， 方法會在單一操作中上傳封存，或使用 Amazon Glacier (Amazon Glacier) 中的分段上傳支援來分段上傳封存。
+ 低階 API 對應接近底層 REST 實作。因此，它提供一個方法，在一個操作中上傳較小的封存，以及一組方法，可支援分段上傳以上傳較大封存。本節說明使用低階 API 以部分形式上傳大型封存。

如需高階和低階的 API 的更多資訊，請參閱 [適用於 Java 的 AWS SDK 搭配 Amazon Glacier 使用](using-aws-sdk-for-java.md)。

**Topics**
+ [使用 的高階 API 分段上傳大型封存 適用於 Java 的 AWS SDK](#uploading-an-archive-in-parts-highlevel-using-java)
+ [使用 的低階 API 分段上傳大型封存 適用於 Java 的 AWS SDK](#uploading-an-archive-mpu-using-java-lowlevel)

## 使用 的高階 API 分段上傳大型封存 適用於 Java 的 AWS SDK
<a name="uploading-an-archive-in-parts-highlevel-using-java"></a>

您可以使用高階 API 的相同方法來上傳小型或大型封存。根據封存大小，高階 API 方法會決定在單一操作中上傳封存，還是使用 Amazon Glacier 提供的分段上傳 API。如需詳細資訊，請參閱[使用 的高階 API 上傳封存 適用於 Java 的 AWS SDK](uploading-an-archive-single-op-using-java.md#uploading-an-archive-single-op-high-level-using-java)。

## 使用 的低階 API 分段上傳大型封存 適用於 Java 的 AWS SDK
<a name="uploading-an-archive-mpu-using-java-lowlevel"></a>

對於精細控制上傳，您可以使用低階 API，您可以設定請求和處理回應。以下是使用 適用於 Java 的 AWS SDK以部分形式上傳大型封存的步驟。

 

1. 建立 `AmazonGlacierClient` 類別的執行個體 (用戶端)。

   您需要指定要儲存封存 AWS 的區域。您使用此用戶端執行的所有操作都會套用到該 AWS 區域。

1. 呼叫 `initiateMultipartUpload` 方法以啟動分段上傳。

   您需要提供要上傳存檔的文件庫名稱、要用於上傳存檔部分的部分大小以及可選說明。您可以透過建立 `InitiateMultipartUploadRequest` 類別的執行個體，來提供這項資訊。在回應中，Amazon Glacier 會傳回上傳 ID。

1. 透過呼叫 `uploadMultipartPart` 方法上傳部分。

   對於您上載的每個部分，您需要提供文件庫名稱、在該部分中上傳的最終組合的存檔中的位元組範圍、部分資料的檢查總和和上傳 ID。

1. 呼叫 `completeMultipartUpload` 方法以計算分段上傳。

   您需要提供上傳 ID、整個封存的檢查總和、封存大小 (您上傳的所有部分的組合大小) 和保存庫名稱。Amazon Glacier 會從上傳的組件建構封存，並傳回封存 ID。

### 範例：使用 在組件中上傳大型封存 適用於 Java 的 AWS SDK
<a name="upload-archive-mpu-java-example"></a>

下列 Java 程式碼範例使用 適用於 Java 的 AWS SDK 將封存上傳至保存庫 (`examplevault`)。如需執行此範例的逐步說明，請參閱 [使用 Eclipse 執行 Amazon Glacier 的 Java 範例](using-aws-sdk-for-java.md#setting-up-and-testing-sdk-java)。您必須如所示，使用要上傳的檔案名稱更新程式碼。

 

**注意**  
此範例對從 1 MB 到 1 GB 的部分大小有效。不過，Amazon Glacier 支援部分大小最多 4 GB。

**Example**  

```
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.glacier.AmazonGlacierClient;
import com.amazonaws.services.glacier.TreeHashGenerator;
import com.amazonaws.services.glacier.model.CompleteMultipartUploadRequest;
import com.amazonaws.services.glacier.model.CompleteMultipartUploadResult;
import com.amazonaws.services.glacier.model.InitiateMultipartUploadRequest;
import com.amazonaws.services.glacier.model.InitiateMultipartUploadResult;
import com.amazonaws.services.glacier.model.UploadMultipartPartRequest;
import com.amazonaws.services.glacier.model.UploadMultipartPartResult;
import com.amazonaws.util.BinaryUtils;

public class ArchiveMPU {

    public static String vaultName = "examplevault";
    // This example works for part sizes up to 1 GB.
    public static String partSize = "1048576"; // 1 MB.
    public static String archiveFilePath = "*** provide archive file path ***";
    public static AmazonGlacierClient client;
    
    public static void main(String[] args) throws IOException {

    	ProfileCredentialsProvider credentials = new ProfileCredentialsProvider();

        client = new AmazonGlacierClient(credentials);
        client.setEndpoint("https://glacier.us-west-2.amazonaws.com/");

        try {
            System.out.println("Uploading an archive.");
            String uploadId = initiateMultipartUpload();
            String checksum = uploadParts(uploadId);
            String archiveId = CompleteMultiPartUpload(uploadId, checksum);
            System.out.println("Completed an archive. ArchiveId: " + archiveId);
            
        } catch (Exception e) {
            System.err.println(e);
        }

    }
    
    private static String initiateMultipartUpload() {
        // Initiate
        InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest()
            .withVaultName(vaultName)
            .withArchiveDescription("my archive " + (new Date()))
            .withPartSize(partSize);            
        
        InitiateMultipartUploadResult result = client.initiateMultipartUpload(request);
        
        System.out.println("ArchiveID: " + result.getUploadId());
        return result.getUploadId();
    }

    private static String uploadParts(String uploadId) throws AmazonServiceException, NoSuchAlgorithmException, AmazonClientException, IOException {

        int filePosition = 0;
        long currentPosition = 0;
        byte[] buffer = new byte[Integer.valueOf(partSize)];
        List<byte[]> binaryChecksums = new LinkedList<byte[]>();
        
        File file = new File(archiveFilePath);
        FileInputStream fileToUpload = new FileInputStream(file);
        String contentRange;
        int read = 0;
        while (currentPosition < file.length())
        {
            read = fileToUpload.read(buffer, filePosition, buffer.length);
            if (read == -1) { break; }
            byte[] bytesRead = Arrays.copyOf(buffer, read);

            contentRange = String.format("bytes %s-%s/*", currentPosition, currentPosition + read - 1);
            String checksum = TreeHashGenerator.calculateTreeHash(new ByteArrayInputStream(bytesRead));
            byte[] binaryChecksum = BinaryUtils.fromHex(checksum);
            binaryChecksums.add(binaryChecksum);
            System.out.println(contentRange);
                        
            //Upload part.
            UploadMultipartPartRequest partRequest = new UploadMultipartPartRequest()
            .withVaultName(vaultName)
            .withBody(new ByteArrayInputStream(bytesRead))
            .withChecksum(checksum)
            .withRange(contentRange)
            .withUploadId(uploadId);               
        
            UploadMultipartPartResult partResult = client.uploadMultipartPart(partRequest);
            System.out.println("Part uploaded, checksum: " + partResult.getChecksum());
            
            currentPosition = currentPosition + read;
        }
        fileToUpload.close();
        String checksum = TreeHashGenerator.calculateTreeHash(binaryChecksums);
        return checksum;
    }

    private static String CompleteMultiPartUpload(String uploadId, String checksum) throws NoSuchAlgorithmException, IOException {
        
        File file = new File(archiveFilePath);

        CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest()
            .withVaultName(vaultName)
            .withUploadId(uploadId)
            .withChecksum(checksum)
            .withArchiveSize(String.valueOf(file.length()));
        
        CompleteMultipartUploadResult compResult = client.completeMultipartUpload(compRequest);
        return compResult.getLocation();
    }
}
```

# 使用 上傳大型封存 適用於 .NET 的 AWS SDK
<a name="uploading-an-archive-mpu-using-dotnet"></a>

適用於 .NET 的 Amazon 開發套件提供的[高階和低階 API](using-aws-sdk.md) 都提供了以部分形式上傳大型封存的方法 (請參閱[在 Amazon Glacier 中上傳封存](uploading-an-archive.md))。

 
+ 高階的 API 提供了一種可用來上傳任何大小的封存的方法。根據您上傳的檔案， 方法會在單一操作中上傳封存，或使用 Amazon Glacier (Amazon Glacier) 中的分段上傳支援來分段上傳封存。
+ 低階 API 對應接近底層 REST 實作。因此，它提供一個方法，在一個操作中上傳較小的封存，以及一組方法，可支援分段上傳以上傳較大封存。本節說明使用低階 API 以部分形式上傳大型封存。

如需高階和低階的 API 的更多資訊，請參閱 [適用於 .NET 的 AWS SDK 搭配 Amazon Glacier 使用](using-aws-sdk-for-dot-net.md)。

**Topics**
+ [使用 的高階 API 分段上傳大型封存 適用於 .NET 的 AWS SDK](#uploading-an-archive-in-parts-highlevel-using-dotnet)
+ [使用 的低階 API 分段上傳大型封存 適用於 .NET 的 AWS SDK](#uploading-an-archive-in-parts-lowlevel-using-dotnet)

## 使用 的高階 API 分段上傳大型封存 適用於 .NET 的 AWS SDK
<a name="uploading-an-archive-in-parts-highlevel-using-dotnet"></a>

您可以使用高階 API 的相同方法來上傳小型或大型封存。根據封存大小，高階 API 方法會決定在單一操作中上傳封存，還是使用 Amazon Glacier 提供的分段上傳 API。如需詳細資訊，請參閱[使用 的高階 API 上傳封存 適用於 .NET 的 AWS SDK](uploading-an-archive-single-op-using-dotnet.md#uploading-an-archive-single-op-highlevel-using-dotnet)。

## 使用 的低階 API 分段上傳大型封存 適用於 .NET 的 AWS SDK
<a name="uploading-an-archive-in-parts-lowlevel-using-dotnet"></a>

對於精細控制上傳，您可以使用低階 API，您可以設定請求和處理回應。以下是使用 適用於 .NET 的 AWS SDK以部分形式上傳大型封存的步驟。

 

1. 建立 `AmazonGlacierClient` 類別的執行個體 (用戶端)。

   您需要指定要儲存封存 AWS 的區域。您使用此用戶端執行的所有操作都會套用到該 AWS 區域。

1. 呼叫 `InitiateMultipartUpload` 方法以啟動分段上傳。

   您需要提供要上傳封存的保存庫名稱、要用於上傳封存部分的部分大小以及可選說明。您可以透過建立 `InitiateMultipartUploadRequest` 類別的執行個體，來提供這項資訊。在回應中，Amazon Glacier 會傳回上傳 ID。

1. 透過呼叫 `UploadMultipartPart` 方法上傳部分。

   對於您上載的每個部分，您需要提供文件庫名稱、在該部分中上傳的最終組合的存檔中的位元組範圍、部分資料的檢查總和和上傳 ID。

1. 呼叫 `CompleteMultipartUpload` 方法以計算分段上傳。

   您需要提供上傳 ID、整個封存的檢查總和、封存大小 (您上傳的所有部分的組合大小) 和保存庫名稱。Amazon Glacier 會從上傳的組件建構封存，並傳回封存 ID。

### 範例：使用適用於 .NET 的 Amazon 開發套件，以部分形式上傳大型封存
<a name="upload-archive-mpu-dotnet-example"></a>

下列 C\$1 程式碼範例使用 適用於 .NET 的 AWS SDK 將封存上傳至保存庫 (`examplevault`)。如需執行此範例的逐步說明，請參閱 [執行程式碼範例](using-aws-sdk-for-dot-net.md#setting-up-and-testing-sdk-dotnet)。您必須如所示，使用要上傳的檔案名稱更新程式碼。

**Example**  

```
using System;
using System.Collections.Generic;
using System.IO;
using Amazon.Glacier;
using Amazon.Glacier.Model;
using Amazon.Runtime;

namespace glacier.amazon.com.rproxy.govskope.us.docsamples
{
  class ArchiveUploadMPU
  {
    static string vaultName       = "examplevault";
    static string archiveToUpload = "*** Provide file name (with full path) to upload ***";
    static long partSize          = 4194304; // 4 MB.

    public static void Main(string[] args)
    {
      AmazonGlacierClient client;
      List<string> partChecksumList = new List<string>();
      try
      {
         using (client = new AmazonGlacierClient(Amazon.RegionEndpoint.USWest2)) 
        {
          Console.WriteLine("Uploading an archive.");
          string uploadId  = InitiateMultipartUpload(client);
          partChecksumList = UploadParts(uploadId, client);
          string archiveId = CompleteMPU(uploadId, client, partChecksumList);
          Console.WriteLine("Archive ID: {0}", archiveId);
        }
        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); }
      Console.WriteLine("To continue, press Enter");
      Console.ReadKey();
    }

    static string InitiateMultipartUpload(AmazonGlacierClient client)
    {
      InitiateMultipartUploadRequest initiateMPUrequest = new InitiateMultipartUploadRequest()
      {

        VaultName = vaultName,
        PartSize = partSize,
        ArchiveDescription = "Test doc uploaded using MPU."
      };

      InitiateMultipartUploadResponse initiateMPUresponse = client.InitiateMultipartUpload(initiateMPUrequest);

      return initiateMPUresponse.UploadId;
    }

    static List<string> UploadParts(string uploadID, AmazonGlacierClient client)
    {
      List<string> partChecksumList = new List<string>();
      long currentPosition = 0;
      var buffer = new byte[Convert.ToInt32(partSize)];

      long fileLength = new FileInfo(archiveToUpload).Length;
      using (FileStream fileToUpload = new FileStream(archiveToUpload, FileMode.Open, FileAccess.Read))
      {
        while (fileToUpload.Position < fileLength)
        {
          Stream uploadPartStream = GlacierUtils.CreatePartStream(fileToUpload, partSize);
          string checksum = TreeHashGenerator.CalculateTreeHash(uploadPartStream);
          partChecksumList.Add(checksum);
          // Upload part.
          UploadMultipartPartRequest uploadMPUrequest = new UploadMultipartPartRequest()
          {

            VaultName = vaultName,
            Body = uploadPartStream,
            Checksum = checksum,
            UploadId = uploadID
          };
          uploadMPUrequest.SetRange(currentPosition, currentPosition + uploadPartStream.Length - 1);
          client.UploadMultipartPart(uploadMPUrequest);

          currentPosition = currentPosition + uploadPartStream.Length;
        }
      }
      return partChecksumList;
    }

    static string CompleteMPU(string uploadID, AmazonGlacierClient client, List<string> partChecksumList)
    {
      long fileLength = new FileInfo(archiveToUpload).Length;
      CompleteMultipartUploadRequest completeMPUrequest = new CompleteMultipartUploadRequest()
      {
        UploadId = uploadID,
        ArchiveSize = fileLength.ToString(),
        Checksum = TreeHashGenerator.CalculateTreeHash(partChecksumList),
        VaultName = vaultName
      };

      CompleteMultipartUploadResponse completeMPUresponse = client.CompleteMultipartUpload(completeMPUrequest);
      return completeMPUresponse.ArchiveId;
    }
  }
}
```

# 使用 REST API 上傳分段中的大型封存
<a name="uploading-an-archive-mpu-using-rest"></a>

如[上傳分段中的大型封存 (分段上傳)](uploading-archive-mpu.md)中所述，分段上傳是指一組操作，可讓您分段上傳封存，並執行相關的操作。如需這些操作的詳細資訊，請參閱下列 API 參考主題：

 
+ [啟動分段上傳 (POST 分段 - 上傳)](api-multipart-initiate-upload.md)
+ [分段上傳 (PUT uploadID)](api-upload-part.md)
+ [完成分段上傳 (POST uploadID)](api-multipart-complete-upload.md)
+ [中止分段上傳 (DELETE uploadID)](api-multipart-abort-upload.md)
+ [清單部分 (GET uploadID)](api-multipart-list-parts.md)
+ [列出分段上傳 (GET 分段 - 上傳)](api-multipart-list-uploads.md)

# 在 Amazon Glacier 中下載封存
<a name="downloading-an-archive"></a>

Amazon Glacier 提供管理主控台，可用來建立和刪除保存庫。不過，您無法使用 管理主控台從 Amazon Glacier 下載封存。若要下載資料，例如相片、影片和其他文件，您必須使用 AWS Command Line Interface (AWS CLI) 或編寫程式碼來提出請求，方法是直接使用 REST API 或使用 AWS SDKs。

如需搭配 使用 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/)。下列主題說明如何使用 適用於 Java 的 AWS SDK、 適用於 .NET 的 AWS SDK和 Amazon Glacier REST API 將封存下載至 Amazon Glacier。

**Topics**
+ [擷取 Amazon Glacier Archives](downloading-an-archive-two-steps.md)
+ [使用 在 Amazon Glacier 中下載封存 適用於 Java 的 AWS SDK](downloading-an-archive-using-java.md)
+ [使用 在 Amazon Glacier 中下載封存 適用於 .NET 的 AWS SDK](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 Archives
<a name="downloading-an-archive-two-steps"></a>

從 Amazon Glacier 擷取封存是一種非同步操作，您會先啟動任務，然後在任務完成後下載輸出。若要啟動封存擷取任務，您可以使用 [啟動任務 (POST 任務)](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 擷取封存是一個兩步驟的程序。以下是此程序的概觀。

**擷取封存**

1. 啟動封存擷取任務。

   1. 取得您想要擷取的封存 ID。您可以從文件庫的清查取得存檔 ID。您可以使用 REST API、 AWS CLI或 AWS SDKs 取得封存 ID。如需詳細資訊，請參閱[在 Amazon Glacier 中下載保存庫庫存](vault-inventory.md)。

   1. 使用 [啟動任務 (POST 任務)](api-initiate-job-post.md)操作啟動請求 Amazon Glacier 準備整個封存或部分封存以進行後續下載的任務。

   當您啟動任務時，Amazon Glacier 會在回應中傳回任務 ID，並以非同步方式執行任務。(如步驟 2 所述，直到工作完成後，您才能下載工作輸出。)
**重要**  
僅適用於標準擷取的資料擷取政策，可能導致 `Initiate Job` 請求失敗，並出現 `PolicyEnforcedException` 例外狀況。如需有關資料擷取政策的詳細資訊，請參閱 [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 輸出)](api-job-output-get.md) 作業下載位元組。

   您可以下載所有位元組，或指定位元組範圍，以僅下載任務輸出的一部分。對於較大的輸出，下載區塊形式的輸出對於發生下載失敗的情況有所幫助，例如網路失敗。如果您在單一請求中取得任務輸出，並且發生網路失敗，此時您必須重頭開始重新下載輸出。不過，如果您以區塊形式下載輸出，當發生任何失敗情況時，您只需重新開始下載較小部分，而不是整個輸出。

Amazon Glacier 必須先完成任務，才能取得其輸出。完成工作之後至少 24 小時內，工作不會過期，意思是您可以在工作完成後 24 小時內下載輸出。還原可能會在任務完成後 24 小時後隨時過期。若要判斷您的任務是否已完成後，您可使用以下其中一個選項來檢查其狀態：
+ **等待任務完成通知** – 您可以指定 Amazon Simple Notification Service (Amazon SNS) 主題，Amazon Glacier 可以在任務完成後發佈通知。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 Retrieval 儲存體類別或 S3 Intelligent-Tiering Archive Access 層中存放的資料。用於規模幾乎最大的封存 (250 MB 以上) 時，使用快速擷取所存取的資料，通常在 1-5 分鐘內即可使用。佈建容量可確保快速擷取在需要時有可用的擷取容量。如需詳細資訊，請參閱[佈建的容量](#api-downloading-an-archive-two-steps-retrieval-expedited-capacity)。
+ **標準**：標準擷取可讓您在幾小時內存取任何封存。標準擷取通常會於 3-5 小時內完成。未指定擷取選項時，擷取請求的預設選項會是「標準」。
+ **大量** – 大量擷取是成本最低的 Amazon Glacier 擷取選項，您可以在一天中以廉價的方式擷取大量資料，甚至是 PB。大量擷取通常會於 5-12 小時內完成。

下表摘要說明封存擷取選項。如需定價的詳細資訊，請參閱 [Amazon Glacier 定價。](https://aws.amazon.com/s3/glacier/pricing/)


| 服務 | 快速 | 標準 | 大批 | 
| --- | --- | --- | --- | 
|  Amazon Glacier  |  1 - 5 分鐘  |  3 - 5 小時  |  5 - 12 小時  | 

若要進行 `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>

佈建容量有助於確保快速擷取在需要時有可用的擷取容量。每個容量單位都提供每 5 分鐘至少可以執行三次「快速」擷取，並提供最多每秒 150 MB (MBps) 的擷取輸送量。

如果工作負載需要非常穩定且可預測的資料子集即時存取，我們建議您購買佈建的擷取容量。但即使沒有佈建的容量，通常仍可進行快速擷取，除非您要擷取的需求量不尋常地高，但此情況很罕見。但是若您需要無論情況如何，皆能存取快速擷取，則必須購買佈建的擷取容量。

#### 購買佈建容量
<a name="downloading-an-archive-purchase-provisioned-capacity"></a>

您可以使用 Amazon Glacier 主控台、[購買佈建容量 (POST 佈建的容量)](api-PurchaseProvisionedCapacity.md)REST API 操作、 AWS SDKs 或 購買佈建容量單位 AWS CLI。如需佈建容量定價資訊，請參閱 [Amazon Glacier 定價](https://aws.amazon.com/s3/glacier/pricing/)。

佈建容量單位會持續一個月，從購買的日期和時間開始。

如果開始日期是在某個月的第 31 天，過期日期則是下個月的最後一天。例如，如果開始日期是 8 月 31 日，過期日期則是 9 月 30 日。如果開始日期是 1 月 31 日，過期日期則是 2 月 28 日。

**使用 Amazon Glacier 主控台購買佈建容量**

1.  登入 AWS 管理主控台 ，並在 [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 MB 為間隔 (1 MB、2 MB、3 MB 等)。

範圍結尾可以是封存的結尾，或任何大於您的範圍開頭的 1 MB 間隔。此外，如果您要在下載資料後取得檢查總和值 (擷取工作完成後)，您在工作啟動請求的範圍，也必須符合樹雜湊。您可以使用檢查總和，來協助確保資料在傳輸期間未遭到損毀。如需有關符合百萬位元組與符合樹雜湊的詳細資訊，請參閱 [下載資料時接收檢查總和](checksum-calculations-range.md)。

# 使用 在 Amazon Glacier 中下載封存 適用於 Java 的 AWS SDK
<a name="downloading-an-archive-using-java"></a>

適用於 Java 的 Amazon 開發套件提供的[高階和低階 API](using-aws-sdk.md) 都提供了下載封存的方法。

**Topics**
+ [使用 的高階 API 下載封存 適用於 Java 的 AWS SDK](#downloading-an-archive-using-java-highlevel-api)
+ [使用 的低階 API 下載封存 適用於 Java 的 AWS SDK](#downloading-an-archive-using-java-lowlevel-api)

## 使用 的高階 API 下載封存 適用於 Java 的 AWS SDK
<a name="downloading-an-archive-using-java-highlevel-api"></a>

高階 API 的 `ArchiveTransferManager` 類別提供可用來下載封存的 `download` 方法。

**重要**  
此 `ArchiveTransferManager` 類別會建立 Amazon Simple Notification Service (Amazon SNS) 主題，以及訂閱該主題的 Amazon Simple Queue Service (Amazon SQS) 佇列。然後啟動封存擷取任務並輪詢佇列以使封存可用。封存可用時，就會開始下載。如需封存擷取時間的詳細資訊，請參閱 [封存擷取選項](downloading-an-archive-two-steps.md#api-downloading-an-archive-two-steps-retrieval-options)。

### 範例：使用 的高階 API 下載封存 適用於 Java 的 AWS SDK
<a name="download-archives-java-highlevel-example"></a>

以下 Java 程式碼範例從美國西部 (奧勒岡) 區域 (`us-west-2`) 中的保存庫 (`examplevault`) 下載封存。

如需執行此範例的逐步說明，請參閱 [使用 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 下載封存 適用於 Java 的 AWS SDK
<a name="downloading-an-archive-using-java-lowlevel-api"></a>

以下是使用 適用於 Java 的 AWS SDK 低階 API 來擷取保存庫庫存的步驟。

 

1. 建立 `AmazonGlacierClient` 類別的執行個體 (用戶端)。

   您需要指定要 AWS 從中下載封存的區域。您使用此用戶端執行的所有操作都會套用到該 AWS 區域。

1. 執行 `archive-retrieval` 方法以啟動 `initiateJob` 任務。

   您可以透過建立 `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 僅準備封存的 1 MB 到 2 MB 部分，從而更新上述請求。

    

   ```
   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 ****");
   ```

   為了回應您的`GetJobOutput`呼叫，如果符合特定條件，Amazon Glacier 會傳回您下載之資料部分的檢查總和。如需詳細資訊，請參閱[下載資料時接收檢查總和](checksum-calculations-range.md)。

   若要確認下載中沒有錯誤，您可以計算用戶端的檢查總和，並將其與回應中Amazon Glacier傳送的檢查總和進行比較。

   對於指定可選範圍的封存擷取任務，當您取得任務說明時，它將包含您正在擷取的範圍的檢查總和 (SHA256TreeHash)。您可以使用此值進一步驗證稍後下載的整個位元組範圍的準確性。例如，如果啟動任務以擷取樹狀雜湊符合的封存範圍，然後以區塊的方式下載輸出，以便每個 `GetJobOutput` 請求傳回檢查總和，則可以計算在用戶端上下載的每個部分的檢查總和，然後計算樹狀雜湊。您可以將其與 Amazon Glacier 傳回的檢查總和進行比較，以回應您的描述任務請求，以確認您下載的整個位元組範圍與存放在 Amazon Glacier 中的位元組範圍相同。

    如需運作範例，請參閱 [範例 2：使用 的低階 API 擷取封存 適用於 Java 的 AWS SDK- 在區塊中下載輸出](#downloading-an-archive-with-range-using-java-example)。

### 範例 1：使用 的低階 API 擷取封存 適用於 Java 的 AWS SDK
<a name="downloading-an-archive-using-java-example"></a>

以下 Java 程式碼範例從指定的保存庫下載封存。任務完成後，該範例將在單一 `getJobOutput` 呼叫中下載整個輸出。如需有關以區塊形式下載輸出的範例，請參閱 [範例 2：使用 的低階 API 擷取封存 適用於 Java 的 AWS SDK- 在區塊中下載輸出](#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 SNS 主題，以便 Amazon Glacier 在完成任務後可以將通知發佈至主題。
+ 定期檢查 Amazon SQS 佇列中是否有包含工作 ID 的訊息。

  如果有訊息，剖析 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 擷取封存 適用於 Java 的 AWS SDK- 在區塊中下載輸出
<a name="downloading-an-archive-with-range-using-java-example"></a>

下列 Java 程式碼範例會從 Amazon Glacier 擷取封存。該程式碼範例透過在 `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 中下載封存 適用於 .NET 的 AWS SDK
<a name="downloading-an-archive-using-dotnet"></a>

適用於 .NET 的 Amazon 開發套件提供的[高階和低階 API](using-aws-sdk.md) 都提供了下載封存的方法。

**Topics**
+ [使用 的高階 API 下載封存 適用於 .NET 的 AWS SDK](#downloading-an-archive-using-dotnet-highlevel-api)
+ [使用 的低階 API 下載封存 適用於 .NET 的 AWS SDK](#downloading-an-archive-using-dotnet-lowlevel-api)

## 使用 的高階 API 下載封存 適用於 .NET 的 AWS SDK
<a name="downloading-an-archive-using-dotnet-highlevel-api"></a>

高階 API 的 `ArchiveTransferManager` 類別提供可用來下載封存的 `Download` 方法。

**重要**  
此 `ArchiveTransferManager` 類別會建立 Amazon Simple Notification Service (Amazon SNS) 主題，以及訂閱該主題的 Amazon Simple Queue Service (Amazon SQS) 佇列。然後啟動封存擷取任務並輪詢佇列以使封存可用。封存可用時，就會開始下載。如需封存擷取時間的詳細資訊，請參閱 [封存擷取選項](downloading-an-archive-two-steps.md#api-downloading-an-archive-two-steps-retrieval-options)。

### 範例：使用 的高階 API 下載封存 適用於 .NET 的 AWS SDK
<a name="download-archives-dotnet-highlevel-example"></a>

以下 C\$1 程式碼範例從美國西部 (奧勒岡) 區域中的保存庫 (`examplevault`) 下載封存。

如需執行此範例的逐步說明，請參閱 [執行程式碼範例](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 下載封存 適用於 .NET 的 AWS SDK
<a name="downloading-an-archive-using-dotnet-lowlevel-api"></a>

以下是使用 的低階 API 下載 Amazon Glacier (Amazon Glacier) 封存的步驟 適用於 .NET 的 AWS SDK。

1. 建立 `AmazonGlacierClient` 類別的執行個體 (用戶端)。

   您需要指定要從中下載封存 AWS 的區域。您使用此用戶端執行的所有操作都會套用到該 AWS 區域。

1. 執行 `archive-retrieval` 方法以啟動 `InitiateJob` 任務。

   您可以透過建立 `InitiateJobRequest`類別的執行個體，提供任務資訊，例如您要下載之封存的封存 ID，以及您希望 Amazon Glacier 發佈任務完成訊息的選用 Amazon SNS 主題。 Amazon Glacier 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 MB 到 2 MB 部分。

   ```
   AmazonGlacierClient client;
   client = new AmazonGlacierClient(Amazon.RegionEndpoint.USWest2);
   
   
   InitiateJobRequest initJobRequest = new InitiateJobRequest()
   {
     VaultName = vaultName,
     JobParameters = new JobParameters()
     {
       Type      = "archive-retrieval",
       ArchiveId = "*** Provide archive id ***",
       SNSTopic  = "*** Provide Amazon SNS topic ARN ***",
     }
   };
   // Specify byte range.
   int ONE_MEG = 1048576;
   initJobRequest.JobParameters.RetrievalByteRange = string.Format("{0}-{1}", ONE_MEG, 2 * ONE_MEG -1);
   
   InitiateJobResponse initJobResponse = client.InitiateJob(initJobRequest);
   string jobId = initJobResponse.JobId;
   ```

1. 等候 工作完成。

   您必須等到任務輸出準備好供您下載。如果您已在保存庫上設定通知組態來識別 Amazon Simple Notification Service (Amazon SNS) 主題，或在啟動任務時指定 Amazon SNS 主題，Amazon Glacier 會在任務完成後傳送訊息至該主題。下一節中提供的程式碼範例使用 Amazon SNS for Amazon Glacier 來發佈訊息。

   您也可以呼叫 `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.
   ```

   為了回應您的`GetJobOutput`呼叫，如果符合特定條件，Amazon Glacier 會傳回您下載之資料部分的檢查總和。如需詳細資訊，請參閱[下載資料時接收檢查總和](checksum-calculations-range.md)。

   若要確認下載中沒有錯誤，您可以在用戶端運算檢查總和，並與回應中傳送的檢查總和 Amazon Glacier 進行比較。

   對於指定的可選範圍的封存擷取任務，當您取得任務描述時，它包括要擷取的範圍的檢查總和 (SHA256TreeHash)。您可以使用此值進一步驗證您稍後下載的整個位元組範圍的準確性。例如，如果啟動任務以擷取樹狀雜湊符合的封存範圍，然後以區塊的方式下載輸出，以便每個 `GetJobOutput` 請求傳回檢查總和，則可以計算在用戶端上下載的每個部分的檢查總和，然後計算樹狀雜湊。您可以將其與 Amazon Glacier 傳回的檢查總和進行比較，以回應您的描述任務請求，以確認您下載的整個位元組範圍與存放在 Amazon Glacier 中的位元組範圍相同。

   

   如需運作範例，請參閱 [範例 2：使用 的低階 API 擷取封存 適用於 .NET 的 AWS SDK- 在區塊中下載輸出](#creating-vaults-sdk-dotnet-example2)。

### 範例 1：使用 的低階 API 擷取封存 適用於 .NET 的 AWS SDK
<a name="creating-vaults-sdk-dotnet-example-retrieve"></a>

以下 C\$1 程式碼範例從指定的保存庫下載封存。任務完成後，該範例將在單一 `GetJobOutput` 呼叫中下載整個輸出。如需有關以區塊形式下載輸出的範例，請參閱 [範例 2：使用 的低階 API 擷取封存 適用於 .NET 的 AWS SDK- 在區塊中下載輸出](#creating-vaults-sdk-dotnet-example2)。

範例會執行下列任務：
+ 設定 Amazon Simple Notification Service (Amazon SNS) 主題 

  Amazon Glacier 會在完成任務後傳送通知至此主題。
+ 設定 Amazon Simple Queue Service (Amazon SQS) 佇列。

  此範例將政策連接至佇列，以使 Amazon SNS 主題能夠發佈訊息。
+ 起始任務以下載指定的封存。

  在任務請求中，範例會指定 Amazon SNS 主題，以便 Amazon Glacier 在完成任務後傳送訊息。
+ 定期檢查 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 擷取封存 適用於 .NET 的 AWS SDK- 在區塊中下載輸出
<a name="creating-vaults-sdk-dotnet-example2"></a>

下列 C\$1 程式碼範例會從 Amazon Glacier 擷取封存。該程式碼範例透過在 `GetJobOutputRequest` 物件中指定位元組範圍來下載區塊中的任務輸出。

```
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using Amazon.Glacier;
using Amazon.Glacier.Model;
using Amazon.Glacier.Transfer;
using Amazon.Runtime;
using Amazon.SimpleNotificationService;
using Amazon.SimpleNotificationService.Model;
using Amazon.SQS;
using Amazon.SQS.Model;
using Newtonsoft.Json;
using System.Collections.Specialized;

namespace glacier.amazon.com.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 已安裝適用於 Python (Boto3) 的 SDK
+ 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*：region 您的保存庫所在的 AWS 區域
   + *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* 和*工作者*參數。
+ Amazon S3 擷取、Amazon SNS 和 Amazon SQS 用量需支付標準 AWS 費用。

# 使用 REST API 下載封存
<a name="downloading-an-archive-using-rest"></a>

**使用 REST API 下載封存**

下載封存是兩個步驟程序。

1. 啟動 `archive-retrieval` 類型的任務。如需詳細資訊，請參閱[啟動任務 (POST 任務)](api-initiate-job-post.md)。

1. 工作完成後，下載封存資料。如需詳細資訊，請參閱[「取得任務輸出」 (GET 輸出)](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 設定。這些命令不會明確提供登入資料，因此會使用預設描述檔的登入資料。
   + 嘗試使用幫助命令。

     ```
     aws help
     ```
   + 若要取得已設定帳戶上的 Amazon Glacier 保存庫清單，請使用 `list-vaults`命令。將 *123456789012* 取代為您的 AWS 帳戶 ID。

     ```
     aws glacier list-vaults --account-id 123456789012
     ```
   + 若要查看 目前的組態資料 AWS CLI，請使用 `aws configure list`命令。

     ```
     aws configure list
     ```

## 範例：使用 下載封存 AWS CLI
<a name="Downloading-Archives-CLI-Implementation"></a>
**注意**  
為了下載封存，您必須知道封存 ID。步驟 1-4 將擷取封存 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
   ```

# 在 Amazon Glacier 中刪除封存
<a name="deleting-an-archive"></a>

您無法使用 Amazon Glacier (Amazon Glacier) 管理主控台刪除封存。若要刪除封存，您必須使用 AWS Command Line Interface (CLI) 或編寫程式碼，直接使用 REST API 或 適用於 Java 的 AWS SDK 和 .NET 包裝函式程式庫提出刪除請求。下列主題說明如何使用 適用於 Java 的 AWS SDK 和 .NET 包裝函式程式庫、REST API 和 AWS CLI。

**Topics**
+ [使用 在 Amazon Glacier 中刪除封存 適用於 Java 的 AWS SDK](deleting-an-archive-using-java.md)
+ [使用 在 Amazon Glacier 中刪除封存 適用於 .NET 的 AWS SDK](deleting-an-archive-using-dot-net.md)
+ [使用 REST API 刪除 Amazon Glacier Archive](deleting-an-archive-using-rest.md)
+ [使用 在 Amazon Glacier 中刪除封存 AWS Command Line Interface](deleting-an-archive-using-cli.md)

您可以一次從保存庫刪除一個封存。若要刪除封存，您必須提在刪除請求中提供其封存 ID。您可以透過為包含封存的保存庫下載保存庫庫存來取得封存 ID。如需下載保存庫庫存的詳細資訊，請參閱[在 Amazon Glacier 中下載保存庫庫存](vault-inventory.md)。

在您刪除封存之後，您可能仍然能夠成功請求起始任務，擷取已刪除的封存，但封存擷取任務將會失敗。

根據以下情況，當您刪除封存時，進行中的封存 ID 擷取可能會也可能不會成功：

 
+ 如果封存擷取任務在 Amazon Glacier 收到刪除封存請求時主動準備資料以供下載，則封存擷取操作可能會失敗。
+ 如果封存擷取任務在 Amazon Glacier 收到刪除封存請求時已成功準備要下載的封存，則您將能夠下載輸出。

如需封存擷取的詳細資訊，請參閱 [在 Amazon Glacier 中下載封存](downloading-an-archive.md)。

此為等冪操作。刪除已刪除的封存不會導致錯誤。

刪除封存之後，如果您立即下載保存庫庫存，它可能會在清單中包含已刪除的封存，因為 Amazon Glacier 每天只會準備一次保存庫庫存。

**注意**  
如需自動刪除保存庫封存，請參閱 [Amazon S3 Glacier 中的自動刪除保存庫封存](https://aws.amazon.com/solutions/guidance/automated-deletion-of-vault-archives-in-amazon-s3-glacier/)。

# 使用 在 Amazon Glacier 中刪除封存 適用於 Java 的 AWS SDK
<a name="deleting-an-archive-using-java"></a>

以下是使用 適用於 Java 的 AWS SDK 低階 API 刪除封存的步驟。

 

1. 建立 `AmazonGlacierClient` 類別的執行個體 (用戶端)。

   您需要指定儲存您要刪除的封存 AWS 的區域。您使用此用戶端執行的所有操作都會套用到該 AWS 區域。

1. 您可以透過建立 `DeleteArchiveRequest` 類別的執行個體來提供請求資訊。

   您需要提供封存 ID、保存庫名稱和您的帳戶 ID。如果您不提供帳戶 ID，則會使用與您提供來簽署請求之登入資料關聯的帳戶 ID。如需詳細資訊，請參閱[適用於 Java 的 AWS SDK 搭配 Amazon Glacier 使用](using-aws-sdk-for-java.md)。

1. 以參數形式提供請求物件，以便執行 `deleteArchive` 方法。

下列 Java 程式碼片段描述前述步驟。

```
AmazonGlacierClient client;

DeleteArchiveRequest request = new DeleteArchiveRequest()
    .withVaultName("*** provide a vault name ***")
    .withArchiveId("*** provide an archive ID ***");

client.deleteArchive(request);
```

 

**注意**  
如需基礎 REST API 的資訊，請參閱 [刪除封存 (DELETE archive)](api-archive-delete.md)。

## 範例：使用 刪除封存 適用於 Java 的 AWS SDK
<a name="deleting-an-archive-using-java-example"></a>

下列 Java 程式碼範例使用 適用於 Java 的 AWS SDK 來刪除封存。如需執行此範例的逐步說明，請參閱 [使用 Eclipse 執行 Amazon Glacier 的 Java 範例](using-aws-sdk-for-java.md#setting-up-and-testing-sdk-java)。您需要如所示，使用保存庫名稱和要刪除之封存的封存 ID 更新程式碼。

**Example**  

```
import java.io.IOException;

import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.glacier.AmazonGlacierClient;
import com.amazonaws.services.glacier.model.DeleteArchiveRequest;

public class ArchiveDelete {

    public static String vaultName = "*** provide vault name ****";
    public static String archiveId = "*** provide archive ID***";
    public static AmazonGlacierClient client;
    
    public static void main(String[] args) throws IOException {
        
    	ProfileCredentialsProvider credentials = new ProfileCredentialsProvider();

        client = new AmazonGlacierClient(credentials);
        client.setEndpoint("https://glacier.us-east-1.amazonaws.com/");        

        try {

            // Delete the archive.
            client.deleteArchive(new DeleteArchiveRequest()
                .withVaultName(vaultName)
                .withArchiveId(archiveId));
            
            System.out.println("Deleted archive successfully.");
            
        } catch (Exception e) {
            System.err.println("Archive not deleted.");
            System.err.println(e);
        }
    }
}
```

# 使用 在 Amazon Glacier 中刪除封存 適用於 .NET 的 AWS SDK
<a name="deleting-an-archive-using-dot-net"></a>

適用於 .NET 的 Amazon 開發套件提供的[高階和低階 API](using-aws-sdk.md) 都提供了刪除封存的方法。

**Topics**
+ [使用 的高階 API 刪除封存 適用於 .NET 的 AWS SDK](#delete-archive-using-dot-net-high-level)
+ [使用低階 API 刪除封存 適用於 .NET 的 AWS SDK](#delete-archive-using-dot-net-low-level)

## 使用 的高階 API 刪除封存 適用於 .NET 的 AWS SDK
<a name="delete-archive-using-dot-net-high-level"></a>

高階 API 的 `ArchiveTransferManager` 類別提供可用來刪除封存的 `DeleteArchive` 方法。

### 範例：使用 的高階 API 刪除封存 適用於 .NET 的 AWS SDK
<a name="delete-archive-dot-net-high-level-example"></a>

下列 C\$1 程式碼範例使用 的高階 API 適用於 .NET 的 AWS SDK 來刪除封存。如需執行此範例的逐步說明，請參閱 [執行程式碼範例](using-aws-sdk-for-dot-net.md#setting-up-and-testing-sdk-dotnet)。您需要如所示，使用要刪除之封存的封存 ID 更新程式碼。

**Example**  

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

namespace glacier.amazon.com.rproxy.govskope.us.docsamples
{
  class ArchiveDeleteHighLevel
  {
    static string vaultName = "examplevault";
    static string archiveId = "*** Provide archive ID ***";

    public static void Main(string[] args)
    {
      try
      {
        var manager = new ArchiveTransferManager(Amazon.RegionEndpoint.USWest2);
        manager.DeleteArchive(vaultName, archiveId);
        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();
    }
  }
}
```

## 使用低階 API 刪除封存 適用於 .NET 的 AWS SDK
<a name="delete-archive-using-dot-net-low-level"></a>

以下是使用 適用於 .NET 的 AWS SDK刪除保存庫的步驟。

 

1. 建立 `AmazonGlacierClient` 類別的執行個體 (用戶端)。

   您需要指定儲存您要刪除的封存 AWS 的區域。您使用此用戶端執行的所有操作都會套用到該 AWS 區域。

1. 您可以透過建立 `DeleteArchiveRequest` 類別的執行個體來提供請求資訊。

   您需要提供封存 ID、保存庫名稱和您的帳戶 ID。如果您不提供帳戶 ID，則會使用與您提供來簽署請求之登入資料關聯的帳戶 ID。如需詳細資訊，請參閱[搭配 Amazon Glacier 使用 AWS SDKs](using-aws-sdk.md)。

1. 以參數形式提供請求物件，以便執行 `DeleteArchive` 方法。

### 範例：使用 的低階 API 刪除封存 適用於 .NET 的 AWS SDK
<a name="delete-archive-dot-net-low-level-example"></a>

下列 C\$1 範例描述前述步驟。此範例使用 的低階 API 適用於 .NET 的 AWS SDK 來刪除封存。

**注意**  
如需基礎 REST API 的資訊，請參閱 [刪除封存 (DELETE archive)](api-archive-delete.md)。

 如需執行此範例的逐步說明，請參閱 [執行程式碼範例](using-aws-sdk-for-dot-net.md#setting-up-and-testing-sdk-dotnet)。您需要如所示，使用要刪除之封存的封存 ID 更新程式碼。

**Example**  

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

namespace glacier.amazon.com.rproxy.govskope.us.docsamples
{
  class ArchiveDeleteLowLevel
  {
    static string vaultName = "examplevault";
    static string archiveId = "*** Provide archive ID ***";

    public static void Main(string[] args)
    {
      AmazonGlacierClient client;
      try
      {
        using (client = new AmazonGlacierClient(Amazon.RegionEndpoint.USWest2))
        {
          Console.WriteLine("Deleting the archive");
          DeleteAnArchive(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); }
      Console.WriteLine("To continue, press Enter");
      Console.ReadKey();
    }

    static void DeleteAnArchive(AmazonGlacierClient client)
    {
      DeleteArchiveRequest request = new DeleteArchiveRequest()
      {
        VaultName = vaultName,
        ArchiveId = archiveId
      };
      DeleteArchiveResponse response = client.DeleteArchive(request);
    }
  }
}
```

# 使用 REST API 刪除 Amazon Glacier Archive
<a name="deleting-an-archive-using-rest"></a>

您可以使用刪除封存 API 來刪除封存。
+ 如需刪除封存 API 的資訊，請參閱 [刪除封存 (DELETE archive)](api-archive-delete.md)。
+ 如需使用 REST API 的詳細資訊，請參閱[Amazon Glacier 的 API 參考](amazon-glacier-api.md)。

# 使用 在 Amazon Glacier 中刪除封存 AWS Command Line Interface
<a name="deleting-an-archive-using-cli"></a>

您可以使用 AWS Command Line Interface () 刪除 Amazon Glacier (Amazon Glacier) 中的封存AWS CLI。

**Topics**
+ [（先決條件） 設定 AWS CLI](#Creating-Vaults-CLI-Setup)
+ [範例：使用 刪除封存 AWS CLI](#Deleting-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 設定。這些命令不會明確提供登入資料，因此會使用預設描述檔的登入資料。
   + 嘗試使用幫助命令。

     ```
     aws help
     ```
   + 若要取得已設定帳戶上的 Amazon Glacier 保存庫清單，請使用 `list-vaults`命令。將 *123456789012* 取代為您的 AWS 帳戶 ID。

     ```
     aws glacier list-vaults --account-id 123456789012
     ```
   + 若要查看 目前的組態資料 AWS CLI，請使用 `aws configure list`命令。

     ```
     aws configure list
     ```

## 範例：使用 刪除封存 AWS CLI
<a name="Deleting-Archives-CLI-Implementation"></a>

1. 使用 [https://docs.aws.amazon.com/cli/latest/reference/glacier/initiate-job.html](https://docs.aws.amazon.com/cli/latest/reference/glacier/initiate-job.html) 命令啟動清查擷取任務。

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

    預期的輸出結果：

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

1. 使用 [https://docs.aws.amazon.com/cli/latest/reference/glacier/describe-job.html](https://docs.aws.amazon.com/cli/latest/reference/glacier/describe-job.html) 命令檢查先前擷取任務的狀態。

   ```
   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. 完成時，請使用 [https://docs.aws.amazon.com/cli/latest/reference/glacier/get-job-output.html](https://docs.aws.amazon.com/cli/latest/reference/glacier/get-job-output.html) 命令將擷取任務下載至檔案 `output.json`。

   ```
   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. 使用 `delete-archive` 命令從文件庫中刪除每個存檔，直到沒有存檔為止。

   ```
   aws glacier delete-archive --vault-name awsexamplevault --account-id 111122223333 --archive-id *** archiveid ***
   ```