使用 IBM Cloud® Object Storage Java SDK

支援將於 2027 年 8 月 6 日結束。 IBM Cloud® Object Storage (COS)SDK v1 將於 2027 年 8 月 6 日停止支援。 此日期之後,該產品將不再獲得更新、安全性修補程式或新版本。 我們建議您遷移至 IBM Cloud Object Storage SDK Java v2,該服務不僅提供更佳的效能、更強大的安全性與現代化的 API,還可持續獲得 IBM 的技術支援。

使用 IBM Cloud® Object Storage Java SDK 來建立客戶端、取得憑證、上傳大型物件,並透過 Key Protect 和 Aspera 管理儲存桶。

IBM Cloud Object Storage SDK for Java 包羅萬象,有許多特性和功能超出本手冊的描述範圍。 如需詳細的類別及方法文件,請參閱 Javadoc。 原始碼可以在 GitHub 儲存庫中找到。

取得 SDK

使用 IBM Cloud Object Storage Java SDK 最簡單的方法是使用 Maven 來管理相依關係。 如果您對 Maven 還不熟悉,可以參考《 5 分鐘 掌握 Maven》指南來快速上手。

Maven 會使用稱為 pom.xml 的檔案,來指定 Java 專案所需的程式庫(及其版本)。 以下是使用 IBM Cloud Object Storage Java SDK 連接至 Object Storage 的範例 pom.xml 檔。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.cos</groupId>
    <artifactId>docs</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>com.ibm.cos</groupId>
            <artifactId>ibm-cos-java-sdk</artifactId>
            <version>2.8.0</version>
        </dependency>
    </dependencies>
</project>

建立用戶端及讀取認證

在下列範例中,是透過提供認證資訊(API 金鑰及服務實例 ID),來建立及配置用戶端 cos。 這些值也可以自動從 credentials 檔案或環境變數中取得。

產生服務認證後,會將產生的 JSON 文件儲存為 ~/.bluemix/cos_credentials。 除非在建立客戶端時明確設定其他憑證,否則 SDK 會自動從此檔案中取得憑證。 如果 cos_credentials 檔案包含 HMAC 金鑰,用戶端將以簽章進行鑑別,否則用戶端會使用提供的 API 金鑰以持有人記號進行鑑別。

如果從 AWS S3 移轉,您也可以使用下列格式從 ~/.aws/credentials 讀取認證資料:

[default]
aws_access_key_id = {API_KEY}
aws_secret_access_key = {SERVICE_INSTANCE_ID}

如果 ~/.bluemix/cos_credentials 和 ~/.aws/credentials 同時存在,則 cos_credentials 會優先。

如需用戶端建構的詳細資料,請參閱 Javadoc。

程式碼範例

在程式碼中,您必須移除這裡提供的角括弧或任何其他多餘字元,以作為圖解。

讓我們先從一個完整範例類別開始,該類別將示範一些基本功能,接著再逐一探討各個類別。 此類 CosExample 別會列出現有儲存桶中的物件、建立新的儲存桶,然後列出該服務實例中的所有儲存桶。

收集必要資訊

  • bucketName 及 newBucketName 是唯一且 DNS 安全的字串。 因為儲存區名稱在整個系統中是唯一的,因此如果此範例執行多次,將需要變更這些值。 請注意,名稱在刪除後會保留 10 到 15 分鐘。
  • apiKey 是 服務憑證 中以 形式呈現的值 apikey。
  • serviceInstanceId 是 服務憑證 中以 形式呈現的值 resource_instance_id。
  • endpointUrl 是一個服務端點 URL,包含 協定 https://。 這並非服務憑證 中所包含的值 endpoints。 如需端點的相關資訊,請參閱端點及儲存空間位置。
  • storageClass 是一個 有效的配置代碼,對應於 值 endpoint。 然後,這會用來作為 S3 API LocationConstraint 變數。
  • location 應該設定為 storageClass 的位置部分。 若為 us-south-standard,這將是 us-south。 此變數僅用於計算 HMAC 簽章,但任何用戶端(包括使用 IAM API 金鑰的這個範例)都需要此變數。
    package com.cos;
    import java.time.LocalDateTime;
    import java.util.List;
    import com.ibm.cloud.objectstorage.ClientConfiguration;
    import com.ibm.cloud.objectstorage.auth.AWSCredentials;
    import com.ibm.cloud.objectstorage.auth.AWSStaticCredentialsProvider;
    import com.ibm.cloud.objectstorage.client.builder.AwsClientBuilder.EndpointConfiguration;
    import com.ibm.cloud.objectstorage.services.s3.AmazonS3;
    import com.ibm.cloud.objectstorage.services.s3.AmazonS3ClientBuilder;
    import com.ibm.cloud.objectstorage.services.s3.model.Bucket;
    import com.ibm.cloud.objectstorage.services.s3.model.ListObjectsRequest;
    import com.ibm.cloud.objectstorage.services.s3.model.ObjectListing;
    import com.ibm.cloud.objectstorage.services.s3.model.S3ObjectSummary;
    import com.ibm.cloud.objectstorage.oauth.BasicIBMOAuthCredentials;
    public class CosExample
    {
        public static void main(String[] args)
        {
            String bucketName = "<BUCKET_NAME>";  // eg my-unique-bucket-name
            String newBucketName = "<NEW_BUCKET_NAME>"; // eg my-other-unique-bucket-name
            String apiKey = "<API_KEY>"; // eg "W00YiRnLW4k3fTjMB-oiB-2ySfTrFBIQQWanc--P3byk"
            String serviceInstanceId = "<SERVICE_INSTANCE_ID"; // eg "crn:v1:bluemix:public:cloud-object-storage:global:a/3bf0d9003abfb5d29761c3e97696b71c:d6f04d83-6c4f-4a62-a165-696756d63903::"
            String endpointUrl = "https://s3.us-south.cloud-object-storage.appdomain.cloud"; // this could be any service endpoint
            String storageClass = "us-south-standard";
            String location = "us"; // not an endpoint, but used in a custom function below to obtain the correct URL
            System.out.println("Current time: " + LocalDateTime.now());
            AmazonS3 cosClient = createClient(apiKey, serviceInstanceId, endpointUrl, location);
            listObjects(cosClient, bucketName);
            createBucket(cosClient, newBucketName, storageClass);
            listBuckets(cosClient);
        }
        public static AmazonS3 createClient(String apiKey, String serviceInstanceId, String endpointUrl, String location)
        {
            AWSCredentials credentials = new BasicIBMOAuthCredentials(apiKey, serviceInstanceId);
            ClientConfiguration clientConfig = new ClientConfiguration()
                    .withRequestTimeout(5000)
                    .withTcpKeepAlive(true);
            return AmazonS3ClientBuilder
                    .standard()
                    .withCredentials(new AWSStaticCredentialsProvider(credentials))
                    .withEndpointConfiguration(new EndpointConfiguration(endpointUrl, location))
                    .withPathStyleAccessEnabled(true)
                    .withClientConfiguration(clientConfig)
                    .build();
        }
        public static void listObjects(AmazonS3 cosClient, String bucketName)
        {
            System.out.println("Listing objects in bucket " + bucketName);
            ObjectListing objectListing = cosClient.listObjects(new ListObjectsRequest().withBucketName(bucketName));
            for (S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) {
                System.out.println(" - " + objectSummary.getKey() + "  " + "(size = " + objectSummary.getSize() + ")");
            }
            System.out.println();
        }
        public static void createBucket(AmazonS3 cosClient, String bucketName, String storageClass)
        {
            cosClient.createBucket(bucketName, storageClass);
        }
        public static void listBuckets(AmazonS3 cosClient)
        {
            System.out.println("Listing buckets");
            final List<Bucket> bucketList = cosClient.listBuckets();
            for (final Bucket bucket : bucketList) {
                System.out.println(bucket.getName());
            }
            System.out.println();
        }
    }

起始設定配置

private static String COS_ENDPOINT = "<endpoint>"; // eg "https://s3.us.cloud-object-storage.appdomain.cloud"
private static String COS_API_KEY_ID = "<api-key>"; // eg "0viPHOY7LbLNa9eLftrtHPpTjoGv6hbLD1QalRXikliJ"
private static String COS_AUTH_ENDPOINT = "https://iam.cloud.ibm.com/identity/token";
private static String COS_SERVICE_CRN = "<resource-instance-id>"; // "crn:v1:bluemix:public:cloud-object-storage:global:a/<CREDENTIAL_ID_AS_GENERATED>:<SERVICE_ID_AS_GENERATED>::"
private static String COS_BUCKET_LOCATION = "<location>"; // eg "us"
public static void main(String[] args)
{
    SDKGlobalConfiguration.IAM_ENDPOINT = COS_AUTH_ENDPOINT;
    try {
        _cos = createClient(COS_API_KEY_ID, COS_SERVICE_CRN, COS_ENDPOINT, COS_BUCKET_LOCATION);
    } catch (SdkClientException sdke) {
        System.out.printf("SDK Error: %s\n", sdke.getMessage());
    } catch (Exception e) {
        System.out.printf("Error: %s\n", e.getMessage());
    }
}
public static AmazonS3 createClient(String api_key, String service_instance_id, String endpoint_url, String location)
{
    AWSCredentials credentials = new BasicIBMOAuthCredentials(api_key, service_instance_id);
    ClientConfiguration clientConfig = new ClientConfiguration().withRequestTimeout(5000);
    clientConfig.setUseTcpKeepAlive(true);
    AmazonS3 cos = AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(credentials))
            .withEndpointConfiguration(new EndpointConfiguration(endpoint_url, location)).withPathStyleAccessEnabled(true)
            .withClientConfiguration(clientConfig).build();
    return cos;
}

金鑰值

  • <endpoint>- 您的雲端物件儲存( Object Storage )的公開端點(可從 IBM Cloud 儀表板取得)。 如需端點的相關資訊,請參閱端點及儲存空間位置。
  • <api-key>- 建立服務憑證時所產生的 API 金鑰(建立與刪除範例需具備寫入權限)
  • <resource-instance-id>- 您的雲端物件儲存( Object Storage )的資源 ID(可透過 IBM Cloud CLI 或 IBM Cloud 儀表板取得 )
  • <location>- 雲端 Object Storage 的預設位置(必須與所使用的區域相符 <endpoint>)

SDK 參照

類別

決定端點

下面的方法可用來根據儲存區位置、端點類型(公用或專用)及特定地區(選用)來決定服務端點。 如需端點的相關資訊,請參閱端點及儲存空間位置。

/**
* Returns a service endpoint based on the
* storage class location (i.e. us-standard, us-south-standard),
* endpoint type (public or private)
*/
public static String getEndpoint(String location, String endPointType) {
    return getEndpoint(location, "", endPointType);
}
/**
* Returns a service endpoint based on the
* storage class location (i.e. us-standard, us-south-standard),
* specific region if desired (i.e. sanjose, amsterdam) - only use if you want a specific regional endpoint,
* endpoint type (public or private)
*/
public static String getEndpoint(String location, String region, String endpointType) {
    HashMap locationMap = new HashMap<String, String>();
    locationMap.put("us", "s3-api.us-geo");
    locationMap.put("us-dallas", "s3-api.dal-us-geo");
    locationMap.put("us-sanjose", "s3-api.sjc-us-geo");
    locationMap.put("us-washington", "s3-api.wdc-us-geo");
    locationMap.put("us-south", "s3.us-south");
    locationMap.put("us-east", "s3.us-east");
    locationMap.put("eu", "s3.eu-geo");
    locationMap.put("eu-amsterdam", "s3.ams-eu-geo");
    locationMap.put("eu-frankfurt", "s3.fra-eu-geo");
/**    locationMap.put("eu-milan", "s3.mil-eu-geo");*/
    locationMap.put("eu-gb", "s3.eu-gb");
    locationMap.put("eu-germany", "s3.eu-de");
    locationMap.put("ap", "s3.ap-geo");
    locationMap.put("ap-tokyo", "s3.tok-ap-geo");
    locationMap.put("che01", "s3.che01");
    locationMap.put("mel01", "s3.mel01");
    locationMap.put("tor01", "s3.tor01");
    String key = location.substring(0, location.lastIndexOf("-")) + (region != null && !region.isEmpty() ? "-" + region : "");
    String endpoint = locationMap.getOrDefault(key, null).toString();
    if (endpoint != null) {
        if (endpointType.toLowerCase() == "private")
            endpoint += ".objectstorage.service.networklayer.com";
        else
            endpoint += ".objectstorage.s3.us-south.cloud-object-storage.appdomain.cloud.net";
    }
    return endpoint;
}

建立新的儲存區

public static void createBucket(String bucketName) {
    System.out.printf("Creating new bucket: %s\n", bucketName);
    _cos.createBucket(bucketName);
    System.out.printf("Bucket: %s created!\n", bucketName);
}

建立具有不同儲存空間類別的儲存區

LocationConstraint 的有效佈建碼清單可以在儲存空間類別手冊中參閱。

cos.createBucket("sample", "us-vault"); // the name of the bucket, and the storage class (LocationConstraint)

SDK 參照

建立新的文字檔

public static void createTextFile(String bucketName, String itemName, String fileText) {
    System.out.printf("Creating new item: %s\n", itemName);
    byte[] arr = fileText.getBytes(StandardCharsets.UTF_8);
    InputStream newStream = new ByteArrayInputStream(arr);
    ObjectMetadata metadata = new ObjectMetadata();
    metadata.setContentLength(arr.length);
    PutObjectRequest req = new PutObjectRequest(bucketName, itemName, newStream, metadata);
    _cos.putObject(req);
    System.out.printf("Item: %s created!\n", itemName);
}

請注意,在將自訂 meta 資料新增至物件時,必須使用 SDK 來建立 ObjectMetadata 物件,而不要手動傳送包含 x-amz-meta-{key} 的自訂標頭。 後者可能會在使用 HMAC 認證進行鑑別時造成問題。

從檔案上傳物件

此範例假設儲存區 sample 已存在。

cos.putObject(
    "sample", // the name of the destination bucket
    "myfile", // the object key
    new File("/home/user/test.txt") // the file name and path of the object to be uploaded
);

使用串流上傳物件

此範例假設儲存區 sample 已存在。

String obj = "An example"; // the object to be stored
ByteArrayOutputStream theBytes = new ByteArrayOutputStream(); // create a new output stream to store the object data
ObjectOutputStream serializer = new ObjectOutputStream(theBytes); // set the object data to be serialized
serializer.writeObject(obj); // serialize the object data
serializer.flush();
serializer.close();
InputStream stream = new ByteArrayInputStream(theBytes.toByteArray()); // convert the serialized data to a new input stream to store
ObjectMetadata metadata = new ObjectMetadata(); // define the metadata
metadata.setContentType("application/x-java-serialized-object"); // set the metadata
metadata.setContentLength(theBytes.size()); // set metadata for the length of the data stream
cos.putObject(
    "sample", // the name of the bucket to which the object is being written
    "serialized-object", // the name of the object being written
    stream, // the name of the data stream writing the object
    metadata // the metadata for the object being written
);

或者,您可以使用 CipherInputStream 來更輕鬆地加密資料串流,而不需要超載現有的 InputStream 物件。

public CipherInputStream encryptStream(InputStream inputStream) {
       // Generate key
       KeyGenerator kgen = KeyGenerator.getInstance("AES");
       kgen.init(128);
       SecretKey aesKey = kgen.generateKey();
       // Encrypt cipher
       Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
       cipher.init(Cipher.ENCRYPT_MODE, aesKey);
       CipherInputStream cis = new CipherInputStream(inputStream, cipher);
       return cis;
}

將物件下載至檔案

此範例假設儲存區 sample 已存在。

GetObjectRequest request = new // create a new request to get an object
GetObjectRequest( // request the new object by identifying
    "sample", // the name of the bucket
    "myFile" // the name of the object
);
s3Client.getObject( // write the contents of the object
    request, // using the request that was just created
    new File("retrieved.txt") // to write to a new file
);

使用串流下載物件

此範例假設儲存區 sample 已存在。

S3Object returned = cos.getObject( // request the object by identifying
    "sample", // the name of the bucket
    "serialized-object" // the name of the serialized object
);
S3ObjectInputStream s3Input = returned.getObjectContent(); // set the object stream

複製物件

// copy an object within the same Bucket
cos.copyObject( // copy the Object, passing…
    "sample",  // the name of the Bucket in which the Object to be copied is stored,
    "myFile.txt",  // the name of the Object being copied from the source Bucket,
    "sample",  // the name of the Bucket in which the Object to be copied is stored,
    "myFile.txt.backup"    // and the new name of the copy of the Object to be copied
);
// copy an object between two Buckets
cos.copyObject( // copy the Object, passing…
    "sample", // the name of the Bucket from which the Object will be copied,
    "myFile.txt", // the name of the Object being copied from the source Bucket,
    "backup", // the name of the Bucket to which the Object will be copied,
    "myFile.txt" // and the name of the copied Object in the destination Bucket
);

SDK 參照

類別

putObject 例外

即使新物件的上傳成功,此方法 putObject 仍可能拋出以下例外:

Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/JAXBException
    at com.ibm.cloud.objectstorage.services.s3.AmazonS3Client.putObject(AmazonS3Client.java:1597)
    at ibmcos.CoSExample.createTextFile(CoSExample.java:174)
    at ibmcos.CoSExample.main(CoSExample.java:65)
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.JAXBException
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:190)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:499)
    ... 3 more

**主要原因:**會將 JAXB API 視為 Java EE API,且不再包含在 Java SE 9 的預設類別路徑上。

**修正:**將下列項目新增至您專案資料夾中的 pom.xml 檔案,並重新包裝專案。

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.0</version>
</dependency>

列出可用的儲存區

public static void getBuckets() {
    System.out.println("Retrieving list of buckets");
    final List<Bucket> bucketList = _cos.listBuckets();
    for (final Bucket bucket : bucketList) {
        System.out.printf("Bucket Name: %s\n", bucket.getName());
    }
}

SDK 參照

類別

方法

列出儲存區中的項目(第 2 版)

AmazonS3 物件包含用來列出內容的更新方法 (listObjectsV2)。 此方法可讓您限制傳回的記錄數,並分批次擷取記錄。 這可能有助於在應用程式內將您的結果進行分頁,並改善效能。

public static void getBucketContentsV2(String bucketName, int maxKeys) {
    System.out.printf("Retrieving bucket contents (V2) from: %s\n", bucketName);
    boolean moreResults = true;
    String nextToken = "";
    while (moreResults) {
        ListObjectsV2Request request = new ListObjectsV2Request()
            .withBucketName(bucketName)
            .withMaxKeys(maxKeys)
            .withContinuationToken(nextToken);
        ListObjectsV2Result result = _cos.listObjectsV2(request);
        for(S3ObjectSummary objectSummary : result.getObjectSummaries()) {
            System.out.printf("Item: %s (%s bytes)\n", objectSummary.getKey(), objectSummary.getSize());
        }
        if (result.isTruncated()) {
            nextToken = result.getNextContinuationToken();
            System.out.println("...More results in next batch!\n");
        }
        else {
            nextToken = "";
            moreResults = false;
        }
    }
    System.out.println("...No more results!");
}

SDK 參照

類別

方法

取得特定項目的檔案內容

public static void getItem(String bucketName, String itemName) {
    System.out.printf("Retrieving item from bucket: %s, key: %s\n", bucketName, itemName);
    S3Object item = _cos.getObject(new GetObjectRequest(bucketName, itemName));
    try {
        final int bufferSize = 1024;
        final char[] buffer = new char[bufferSize];
        final StringBuilder out = new StringBuilder();
        InputStreamReader in = new InputStreamReader(item.getObjectContent());
        for (; ; ) {
            int rsz = in.read(buffer, 0, buffer.length);
            if (rsz < 0)
                break;
            out.append(buffer, 0, rsz);
        }
        System.out.println(out.toString());
    } catch (IOException ioe){
        System.out.printf("Error reading file %s: %s\n", name, ioe.getMessage());
    }
}

SDK 參照

類別

方法

從儲存區刪除項目

public static void deleteItem(String bucketName, String itemName) {
    System.out.printf("Deleting item: %s\n", itemName);
    _cos.deleteObject(bucketName, itemName);
    System.out.printf("Item: %s deleted!\n", itemName);
}

SDK 參照

方法

從儲存區刪除多個項目

刪除要求最多可以包含您要刪除的 1000 個金鑰。 雖然這對於降低每次請求的效能損失非常有用,但在刪除大量金鑰時請務必謹慎。 此外,也請考量物件的大小,以確保適當的效能。

public static void deleteItems(String bucketName) {
    DeleteObjectsRequest req = new DeleteObjectsRequest(bucketName);
    req.withKeys(
        "deletetest/testfile1.txt",
        "deletetest/testfile2.txt",
        "deletetest/testfile3.txt",
        "deletetest/testfile4.txt",
        "deletetest/testfile5.txt"
    );
    DeleteObjectsResult res = _cos.deleteObjects(req);
    System.out.printf("Deleted items for %s\n", bucketName);
    List<DeleteObjectsResult.DeletedObject> deletedItems = res.getDeletedObjects();
    for(DeleteObjectsResult.DeletedObject deletedItem : deletedItems) {
        System.out.printf("Deleted item: %s\n", deletedItem.getKey());
    }
}

SDK 參照

類別

方法

刪除儲存區

public static void deleteBucket(String bucketName) {
    System.out.printf("Deleting bucket: %s\n", bucketName);
    _cos.deleteBucket(bucketName);
    System.out.printf("Bucket: %s deleted!\n", bucketName);
}

SDK 參照

方法

檢查物件是否可公開讀取

public static void getItemACL(String bucketName, String itemName) {
    System.out.printf("Retrieving ACL for %s from bucket: %s\n", itemName, bucketName);
    AccessControlList acl = _cos.getObjectAcl(bucketName, itemName);
    List<Grant> grants = acl.getGrantsAsList();
    for (Grant grant : grants) {
        System.out.printf("User: %s (%s)\n", grant.getGrantee().getIdentifier(), grant.getPermission().toString());
    }
}

SDK 參照

類別

方法

執行多部分上傳

public static void multiPartUpload(String bucketName, String itemName, String filePath) {
    File file = new File(filePath);
    if (!file.isFile()) {
        System.out.printf("The file '%s' does not exist or is not accessible.\n", filePath);
        return;
    }
    System.out.printf("Starting multi-part upload for %s to bucket: %s\n", itemName, bucketName);
    InitiateMultipartUploadResult mpResult = _cos.initiateMultipartUpload(new InitiateMultipartUploadRequest(bucketName, itemName));
    String uploadID = mpResult.getUploadId();
    //begin uploading the parts
    //min 5MB part size
    long partSize = 1024 * 1024 * 5;
    long fileSize = file.length();
    long partCount = ((long)Math.ceil(fileSize / partSize)) + 1;
    List<PartETag> dataPacks = new ArrayList<PartETag>();
    try {
        long position = 0;
        for (int partNum = 1; position < fileSize; partNum++) {
            partSize = Math.min(partSize, (fileSize - position));
            System.out.printf("Uploading to %s (part %s of %s)\n", name, partNum, partCount);
            UploadPartRequest upRequest = new UploadPartRequest()
                    .withBucketName(bucketName)
                    .withKey(itemName)
                    .withUploadId(uploadID)
                    .withPartNumber(partNum)
                    .withFileOffset(position)
                    .withFile(file)
                    .withPartSize(partSize);
            UploadPartResult upResult = _cos.uploadPart(upRequest);
            dataPacks.add(upResult.getPartETag());
            position += partSize;
        }
        //complete upload
        _cos.completeMultipartUpload(new CompleteMultipartUploadRequest(bucketName, itemName, uploadID, dataPacks));
        System.out.printf("Upload for %s Complete!\n", itemName);
    } catch (SdkClientException sdke) {
        System.out.printf("Multi-part upload aborted for %s\n", itemName);
        System.out.printf("Upload Error: %s\n", sdke.getMessage());
        _cos.abortMultipartUpload(new AbortMultipartUploadRequest(bucketName, itemName, uploadID));
    }
}

SDK 參照

類別

方法

建立備份政策

public static void main(String[] args) {
        try {
            // Initialize authenticator
            IamAuthenticator authenticator = new IamAuthenticator.Builder()
                    .apikey(API_KEY)
                    .build();
            // Initialize ResourceConfiguration client
            ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);
            // Generate unique backup vault name
            String backupVaultName = "vault-" + UUID.randomUUID().toString();
            // Create backup policy
            CreateBackupPolicyOptions backupPolicyOptions = new CreateBackupPolicyOptions.Builder()
                    .bucket(SOURCE_BUCKET_NAME)
                    .initialRetention(new DeleteAfterDays.Builder().deleteAfterDays(1).build())
                    .policyName(BACKUP_POLICY_NAME)
                    .targetBackupVaultCrn(BACKUP_VAULT_CRN)
                    .backupType("continuous").build();
            Response<BackupPolicy> createResult = rcClient.createBackupPolicy(backupPolicyOptions).execute();
            System.out.println("Policy Name:");
            System.out.println(createResult.getResult().getPolicyName());
        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
            e.printStackTrace();
        }
    }

列出備份政策

    public static void main(String[] args) {
            try {
                // Initialize IAM authenticator and Resource Configuration client
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);
                // List all backup policies
                ListBackupPoliciesOptions listOptions = new ListBackupPoliciesOptions.Builder()
                        .bucket(SOURCE_BUCKET_NAME)
                        .build();
                Response<BackupPolicyCollection> listResponse = rcClient.listBackupPolicies(listOptions).execute();
                System.out.println("\nList of backup policies:");
                List<?> policies = listResponse.getResult().getBackupPolicies();
                for (Object policy : policies) {
                    System.out.println(policy);
                }
            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

取得備份政策

    public static void main(String[] args) {
            try {
                // Setup IAM Authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();
                // Initialize Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);
                // Generate unique policy name
                String policyName = "policy_name_" + UUID.randomUUID().toString();
                // Fetch backup policy using policy ID
                GetBackupPolicyOptions getOptions = new GetBackupPolicyOptions.Builder()
                        .bucket(SOURCE_BUCKET_NAME)
                        .policyId(POLICY_ID)
                        .build();
                Response<BackupPolicy> getResponse = rcClient.getBackupPolicy(getOptions).execute();
                BackupPolicy fetchedPolicy = getResponse.getResult();
                System.out.println("\nFetched Backup Policy Details:");
                System.out.println(fetchedPolicy);
            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

刪除備份原則

    public static void main(String[] args) {
            try {
                // Setup IAM Authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();
                // Initialize Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);
                // Delete the created backup policy
                DeleteBackupPolicyOptions deleteOptions = new DeleteBackupPolicyOptions.Builder()
                        .bucket(SOURCE_BUCKET_NAME)
                        .policyId(POLICY_ID)
                        .build();
                rcClient.deleteBackupPolicy(deleteOptions).execute();
                System.out.printf("Backup policy '%s' deleted successfully.%n", POLICY_ID);
            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

建立備份儲存庫

    public static void main(String[] args) {
            try {
                // Setup IAM Authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();
                // Initialize Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);
                // Generate unique backup vault name
                String backupVaultName = "backup-vault-" + UUID.randomUUID();
                // Create backup vault
                CreateBackupVaultOptions createOptions = new CreateBackupVaultOptions.Builder()
                        .serviceInstanceId(SERVICE_INSTANCE_ID)
                        .backupVaultName(BACKUP_VAULT_NAME)
                        .region(REGION)
                        .build();
                Response<BackupVault> response = rcClient.createBackupVault(createOptions).execute();
                BackupVault vault = response.getResult();
                System.out.println("Backup vault created:");
                System.out.println(vault);
            } catch (Exception e) {
                System.err.println("Error creating backup vault: " + e.getMessage());
                e.printStackTrace();
            }
        }

列出備份儲存庫

    public static void main(String[] args) {
            try {
                // Setup IAM Authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();
                // Initialize Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);
                // List backup vaults
                ListBackupVaultsOptions listBackupVaultsOptions = new ListBackupVaultsOptions.Builder().
                        serviceInstanceId(SERVICE_INSTANCE_ID).build();
                Response<BackupVaultCollection> backupVaults = rcClient.listBackupVaults(listBackupVaultsOptions).execute();
                System.out.println("\nList of backup vaults:");
                if ( backupVaults.getResult().getBackupVaults() != null) {
                    for (String vault :  backupVaults.getResult().getBackupVaults()) {
                        System.out.println(vault);
                    }
                } else {
                    System.out.println("No backup vaults found.");
                }
            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

取得備份儲存庫

    public static void main(String[] args) {
            try {
                // Initialize IAM Authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();
                // Create Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);
                // Generate unique backup vault name
                String backupVaultName = "backup-vault-" + UUID.randomUUID();
                // Get backup vault details
                GetBackupVaultOptions getOptions = new GetBackupVaultOptions.Builder()
                        .backupVaultName(BACKUP_VAULT_NAME)
                        .build();
                Response<BackupVault> getResponse = rcClient.getBackupVault(getOptions).execute();
                BackupVault vaultDetails = getResponse.getResult();
                System.out.println("Backup vault details:");
                System.out.println(vaultDetails);
            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

更新備份儲存庫

    public static void main(String[] args) {
            try {
                // Setup IAM Authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();
                // Initialize Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);
                // Update vault: disable activity tracking and metrics monitoring
                BackupVaultPatch backupVaultPatch = new BackupVaultPatch.Builder()
                        .activityTracking(new BackupVaultActivityTracking.Builder().managementEvents(Boolean.FALSE).build())
                        .metricsMonitoring(new BackupVaultMetricsMonitoring.Builder().usageMetricsEnabled(Boolean.FALSE).build())
                        .build();
                UpdateBackupVaultOptions updateBackupVaultOptions = new UpdateBackupVaultOptions.Builder()
                        .backupVaultName(backupVaultName)
                        .backupVaultPatch(backupVaultPatch.asPatch()).build();
                Response<BackupVault> backupVaultResponse2 = rcClient.updateBackupVault(updateBackupVaultOptions).execute();
            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

刪除備份儲存庫

    public static void main(String[] args) {
            try {
                // Set up the authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();
                // Initialize Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);
                // Delete backup vault
                DeleteBackupVaultOptions deleteOptions = new DeleteBackupVaultOptions.Builder()
                        .backupVaultName(BACKUP_VAULT_NAME)
                        .build();
                Response<Void> deleteResponse = rcClient.deleteBackupVault(deleteOptions).execute();
                System.out.println("Failed to delete backup vault '" + BACKUP_VAULT_NAME + "'.");
            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

列名復原範圍

    public static void main(String[] args) {
            try {
                // Setup authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();
                // Initialize Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);
                // List recovery ranges
                ListRecoveryRangesOptions recoveryRangesOptions = new ListRecoveryRangesOptions.Builder()
                        .backupVaultName(BACKUP_VAULT_NAME)
                        .build();
                Response<RecoveryRangeCollection> recoveryRangesResponse = rcClient.listRecoveryRanges(recoveryRangesOptions).execute();
                System.out.println("Recovery Ranges:");
                System.out.println(recoveryRangesResponse.getResult());
            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

取得復原範圍

    public static void main(String[] args) {
            try {
                // Setup authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();
                // Initialize Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);
                // Fetch details of the recovery range
                GetSourceResourceRecoveryRangeOptions recoveryRangeOptions = new GetSourceResourceRecoveryRangeOptions.Builder()
                        .backupVaultName(BACKUP_VAULT_NAME)
                        .recoveryRangeId(RECOVERY_RANGE_ID)
                        .build();
                Response<RecoveryRange> getRecoveryRangeResponse = rcClient.getSourceResourceRecoveryRange(recoveryRangeOptions).execute();
                System.out.println("Recovery Range Details:");
                System.out.println(getRecoveryRangeResponse.getResult());
            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

更新復原範圍

    public static void main(String[] args) {
            try {
                // Setup authenticator
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();
                // Initialize Resource Configuration client
                ResourceConfiguration rcClient = new ResourceConfiguration("resource-configuration", authenticator);
                // Patch the recovery range (update retention to 99 days)
                PatchSourceResourceRecoveryRangeOptions patchOptions = new PatchSourceResourceRecoveryRangeOptions.Builder()
                        .backupVaultName(BACKUP_VAULT_NAME)
                        .recoveryRangeId(RECOVERY_RANGE_ID)
                        .recoveryRangePatch(
                                new RecoveryRangePatch.Builder()
                                        .retention(new DeleteAfterDays.Builder().deleteAfterDays(99).build())
                                        .build()
                        )
                        .build();
                Response<RecoveryRange> patchResponse = rcClient.patchSourceResourceRecoveryRange(patchOptions).execute();
                System.out.println("Recovery Range successfully patched:");
                System.out.println(patchResponse.getResult());
            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

啟動還原

    public static void main(String[] args) {
            try {
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();
                ResourceConfiguration RC_CLIENT = new ResourceConfiguration("resource-configuration", authenticator);
                 CreateRestoreOptions  createRestoreOptions = new CreateRestoreOptions.Builder()
                         .backupVaultName(BACKUP_VAULT_NAME)
                         .recoveryRangeId(recoveryRangeId)
                         .restoreType("in_place")
                         .targetResourceCrn(TARGET_BUCKET_CRN)
                         .restorePointInTime(RESTORE_TIME)
                         .build();
                 Response<Restore> createRestoreCall = RC_CLIENT.createRestore(createRestoreOptions).execute();
                 String restoreId = createRestoreCall.getResult().getRestoreId();
                 GetRestoreOptions getRestoreOptions = new GetRestoreOptions.Builder().restoreId(restoreId).backupVaultName(backupVaultName).build();
                 Response<Restore> restoreResult = RC_CLIENT.getRestore(getRestoreOptions).execute();
                 System.out.println("Restore successfully:");
                 System.out.println(restoreResult);
            } catch (Exception e) {
                System.err.println("Error: " + e.getMessage());
                e.printStackTrace();
            }
        }

列名還原

    public static void main(String[] args) {
            try {
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();
                ResourceConfiguration RC_CLIENT = new ResourceConfiguration("resource-configuration", authenticator);
                ListRestoresOptions listRestoreOptions = new ListRestoresOptions.Builder()
                        .backupVaultName(BACKUP_VAULT_NAME)
                        .build();
                Response<RestoreList> listRestoreResponse = rcClient.listRestores(listRestoreOptions).execute();
                System.out.println("Restore operations: " + listRestoreResponse.getResult());
           } catch (Exception e) {
               System.err.println("Error: " + e.getMessage());
               e.printStackTrace();
           }
        }

取得還原詳細資訊

    public static void main(String[] args) {
            try {
                IamAuthenticator authenticator = new IamAuthenticator.Builder()
                        .apikey(API_KEY)
                        .build();
                ResourceConfiguration RC_CLIENT = new ResourceConfiguration("resource-configuration", authenticator);
                Response<Restore> getRestoreOptions =
                        GetRestoreOptions.Builder()
                        .restoreId(restoreId)
                        .backupVaultName(BACKUP_VAULT_NAME)
                        .build();
                Response<Restore> restoreResult = RC_CLIENT.getRestore(getRestoreOptions).execute();
                System.out.println("Get Restore: " + restoreResult);
           } catch (Exception e) {
               System.err.println("Error: " + e.getMessage());
               e.printStackTrace();
           }
        }

建立一個啟用物件鎖定功能的新 cos 儲存桶

    public static void createBucket(String bucketName, AmazonS3 _cosClient)
        {
            _cosClient.createBucket(bucketName);
            System.out.printf("Bucket: %s created!\n", bucketName);
        }

在 Object Storage 儲存桶上設定符合合規模式的物件鎖定配置

    public static void putObjectLockConfiguration(String bucketName, AmazonS3 _cosClient)
        {
            DefaultRetention defRet = new DefaultRetention()
                    .withMode(ObjectLockRetentionMode.COMPLIANCE)
                    .withDays(1);
            ObjectLockRule objRule = new ObjectLockRule()
                            .withDefaultRetention(defRet);
            ObjectLockConfiguration objConfig = new ObjectLockConfiguration()
                            .withObjectLockEnabled(ObjectLockEnabled.ENABLED)
                            .withRule(objRule);
            SetObjectLockConfigurationRequest objSet = new SetObjectLockConfigurationRequest()
                            .withBucketName(BUCKET_NAME)
                            .withObjectLockConfiguration(objConfig);
            _cosClient.setObjectLockConfiguration(objSet);
            System.out.printf("Successfully added object lock cofiguration on : %s\n", bucketName);
        }

在 Object Storage 儲存桶上設定具備治理模式的物件鎖定配置

    public static void putObjectLockConfigurationWithGovernanceMode(String bucketName, AmazonS3 _cosClient)
        {
            DefaultRetention defRet = new DefaultRetention()
                    .withMode(ObjectLockRetentionMode.GOVERNANCE)
                    .withDays(1);
            ObjectLockRule objRule = new ObjectLockRule()
                            .withDefaultRetention(defRet);
            ObjectLockConfiguration objConfig = new ObjectLockConfiguration()
                            .withObjectLockEnabled(ObjectLockEnabled.ENABLED)
                            .withRule(objRule);
            SetObjectLockConfigurationRequest objSet = new SetObjectLockConfigurationRequest()
                            .withBucketName(BUCKET_NAME)
                            .withObjectLockConfiguration(objConfig);
            _cosClient.setObjectLockConfiguration(objSet);
            System.out.printf("Successfully added object lock cofiguration on : %s\n", bucketName);
        }

取得 Object Storage 儲存桶的物件鎖定設定

    public static void getObjectLockConfigurationWithGovernanceMode(String bucketName, AmazonS3 _cosClient)
        {
            GetObjectLockConfigurationRequest objReq = new GetObjectLockConfigurationRequest().withBucketName(BUCKET_NAME);
            GetObjectLockConfigurationResult objRes = _cosClient.getObjectLockConfiguration(objReq);
            ObjectLockConfiguration objLckConfig = objRes.getObjectLockConfiguration();
            ObjectLockRule objGetRule = objLckConfig.getRule();
            System.out.printf("ObjectLock Configuration : %s\n", objGetRule);
        }

將具有治理模式的物件上傳至 Object Storage 儲存桶

    public static void uploadFileWithGovernanceMode(String bucketName, String itemName, String fileText) {
            System.out.printf("Creating new item: %s\n", itemName);
            LocalDate date = LocalDate.of(2025, 11, 11);
            InputStream newStream = new ByteArrayInputStream(fileText.getBytes(Charset.forName("UTF-8")));
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(fileText.length());
            PutObjectRequest req = new PutObjectRequest(bucketName, itemName, newStream, metadata)
                                .withObjectLockMode("GOVERNANCE")
                                .withObjectLockRetainUntilDate(date);
            _cosClient.putObject(req);
            System.out.printf("Item: %s created!\n", itemName);
        }

在物件上啟用物件鎖保留與合規模式

    public static void putObjectLockRetention(String bucketName,String itemName, AmazonS3 _cosClient)
        {
            LocalDate date = LocalDate.of(2025, 11, 11);
            ObjectLockRetention objRet = new ObjectLockRetention()
                        .withMode("COMPLIANCE")
                        .withRetainUntilDate(date);
            SetObjectRetentionRequest objSet = new SetObjectRetentionRequest()
                        .withBucketName(BUCKET_NAME)
                        .withitemName(itemName)
                        .withRetention(objRet);
                        .withBypassGovernanceRetention(true);
            _cosClient.setObjectRetention(objSet);
            System.out.printf("Successfully added object retention on : %s\n", itemName);
        }

在物件上啟用物件鎖保留與治理模式

    public static void putObjectLockRetentionWithGovernanceMode(String bucketName,String itemName, AmazonS3 _cosClient)
        {
            LocalDate date = LocalDate.of(2025, 11, 11);
            ObjectLockRetention objRet = new ObjectLockRetention()
                        .withMode("GOVERNANCE")
                        .withRetainUntilDate(date);
            SetObjectRetentionRequest objSet = new SetObjectRetentionRequest()
                        .withBucketName(BUCKET_NAME)
                        .withitemName(itemName)
                        .withRetention(objRet);
                        .withBypassGovernanceRetention(true);
            _cosClient.setObjectRetention(objSet);
            System.out.printf("Successfully added object retention on : %s\n", itemName);
        }

取得物件鎖保留

    public static void getObjectLockRetentionWithGovernanceMode(String bucketName,String itemName, AmazonS3 _cosClient)
        {
            GetObjectRetentionRequest objReq = new GetObjectRetentionRequest()
                .withBucketName(BUCKET_NAME)
                .withitemName(itemName);
            GetObjectRetentionResult objRes1 = _cosClient.getObjectRetention(objReq);
            ObjectLockRetention objRet1 = objRes1.getRetention();
            System.out.printf("Retention : %s\n", objRet1);
        }

使用繞過治理刪除具有物件鎖治理模式的物件

    public static void deleteObjectWithBypassGovernance(String bucketName, String itemName) {
            System.out.printf("Deleting item: %s\n", itemName);
            DeleteObjectRequest deleteRequest = new DeleteObjectRequest(BUCKET_NAME, Key)
                .withBypassGovernanceRetention(true);
            _cosClient.deleteObject(deleteRequest);
            System.out.printf("Item: %s deleted!\n", itemName);
        }

使用 Transfer Manager 上傳較大的物件

TransferManager 可簡化大型檔案傳送,方法是在必須設定配置參數時自動併入多部分上傳。

public static void largeObjectUpload(String bucketName, String itemName, String filePath) throws IOException, InterruptedException {
    File uploadFile = new File(filePath);
    if (!uploadFile.isFile()) {
        System.out.printf("The file '%s' does not exist or is not accessible.\n", filePath);
        return;
    }
    System.out.println("Starting large file upload with TransferManager");
    //set the part size to 5 MB
    long partSize = 1024 * 1024 * 5;
    //set the threshold size to 5 MB
    long thresholdSize = 1024 * 1024 * 5;
    String endPoint = getEndpoint(COS_BUCKET_LOCATION, "public");
    AmazonS3 s3client = createClient(COS_API_KEY_ID, COS_SERVICE_CRN, endPoint, COS_BUCKET_LOCATION);
    TransferManager transferManager = TransferManagerBuilder.standard()
        .withS3Client(s3client)
        .withMinimumUploadPartSize(partSize)
        .withMultipartCopyThreshold(thresholdSize)
        .build();
    try {
        Upload lrgUpload = transferManager.upload(bucketName, itemName, uploadFile);
        lrgUpload.waitForCompletion();
        System.out.println("Large file upload complete!");
    }
    catch (SdkClientException e) {
        System.out.printf("Upload error: %s\n", e.getMessage());
    }
    finally {
        transferManager.shutdownNow();
    }

SDK 參照

類別

方法

使用 Key Protect

Key Protect 可新增至儲存空間儲存區,以加密雲端中靜止的機密資料。

開始之前

若要建立啟用 Key-Protect 的儲存桶,需具備以下項目:

擷取根金鑰 CRN

  1. 擷取 Key Protect 服務的實例 ID
  2. 使用 Key Protect API 來擷取所有可用金鑰
  3. 檢索您用於在儲存桶上啟用 Key Protect 功能的根金鑰之 CRN。 CRN 的格式類似於以下範例:

crn:v1:bluemix:public:kms:us-south:a/3d624cd74a0dea86ed8efe3101341742:90b6a1db-0fe1-4fe9-b91e-962c327df531:key:0bg3e33e-a866-50f2-b715-5cba2bc93234

建立儲存區並啟用 key-protect

private static String COS_KP_ALGORITHM = "<algorithm>";
private static String COS_KP_ROOTKEY_CRN = "<root-key-crn>";
public static void createBucketKP(String bucketName) {
    System.out.printf("Creating new encrypted bucket: %s\n", bucketName);
    EncryptionType encType = new EncryptionType();
    encType.setKmsEncryptionAlgorithm(COS_KP_ALGORITHM);
    encType.setIBMSSEKMSCustomerRootKeyCrn(COS_KP_ROOTKEY_CRN);
    CreateBucketRequest req = new CreateBucketRequest(bucketName).withEncryptionType(encType);
    _cos.createBucket(req);
    System.out.printf("Bucket: %s created!", bucketName);
}

金鑰值

  • <algorithm>- 新增至儲存桶的物件所使用的加密演算法(預設為 AES256 )。
  • <root-key-crn>- 從 Key Protect 服務取得的根金鑰 (Root Key) 的 CRN。

SDK 參照

類別

方法

Key Protect 的新標頭

其他標頭已定義在 Headers 類別內:

public static final String IBM_SSE_KP_ENCRYPTION_ALGORITHM = "ibm-sse-kp-encryption-algorithm";
public static final String IBM_SSE_KP_CUSTOMER_ROOT_KEY_CRN = "ibm-sse-kp-customer-root-key-crn";

在建立儲存桶實作的同一個區段中,除了已新增 IAM 服務實例標頭外,還新增了 2 個加密標頭:

//Add IBM Service Instance Id & Encryption to headers
if ((null != this.awsCredentialsProvider ) && (this.awsCredentialsProvider.getCredentials() instanceof IBMOAuthCredentials)) {
    IBMOAuthCredentials oAuthCreds = (IBMOAuthCredentials)this.awsCredentialsProvider.getCredentials();
    if (oAuthCreds.getServiceInstanceId() != null) {
        request.addHeader(Headers.IBM_SERVICE_INSTANCE_ID, oAuthCreds.getServiceInstanceId());
        request.addHeader(Headers.IBM_SSE_KP_ENCRYPTION_ALGORITHM, createBucketRequest.getEncryptionType().getKpEncryptionAlgorithm());
        request.addHeader(Headers.IBM_SSE_KP_CUSTOMER_ROOT_KEY_CRN, createBucketRequest.getEncryptionType().getIBMSSEKPCustomerRootKeyCrn());
    }
}

已更新 和 ObjectListing HeadBucketResult 物件,新增包含布林型 及 IBMSSEKPEnabled 字串型 IBMSSEKPCustomerRootKeyCrn 變數,並附帶 getter 與 setter 方法。 这些会储存新标头的值。

GET 儲存區

public ObjectListing listObjects(String bucketName)
public ObjectListing listObjects(String bucketName, String prefix)
public ObjectListing listObjects(ListObjectsRequest listObjectsRequest)

該 ObjectListing 類別需要 2 個額外的方法:

ObjectListing listing = s3client.listObjects(listObjectsRequest)
String KPEnabled = listing.getIBMSSEKPEnabled();
String crkId = listing.getIBMSSEKPCrkId();

額外的標題已在 Headers 類別中定義:

Headers.java
public static final string IBM_SSE_KP_ENABLED = "ibm-sse-kp-enabled";
public static final String IBM_SSE_KP_CUSTOMER_ROOT_KEY_CRN = "ibm-sse-kp-customer-root-key-crn";

S3XmlResponseHandler 負責取消配置所有 XML 回應。 已新增一項檢查,確保結果為 的實例,ObjectListing 且檢索到的標頭已新增至 物件 ObjectListing 中:

if (result instanceof ObjectListing) {
    if (!StringUtils.isNullOrEmpty(responseHeaders.get(Headers.IBM_SSE_KP_ENABLED)){
            ((ObjectListing) result).setIBMSSEKPEnabled(Boolean.parseBoolean(responseHeaders.get(Headers.IBM_SSE_KP_ENABLED)));
        }
    if (!StringUtils.isNullOrEmpty(responseHeaders.get(Headers.IBM_SSE_KP_CUSTOMER_ROOT_KEY_CRN))) {
            ((ObjectListing) result).setIBMSSEKPCrk(responseHeaders.get(Headers.IBM_SSE_KP_CUSTOMER_ROOT_KEY_CRN));
        }
}

HEAD 儲存區

其他標頭已定義在 Headers 類別內:

Headers.java
public static final String IBM_SSE_KP_ENABLED = "ibm-sse-kp-enabled";
public static final String IBM_SSE_KP_CUSTOMER_ROOT_KEY_CRN = "ibm-sse-kp-customer-root-key-crn";

這些變數會移入 HeadBucketResponseHandler 中。

HeadBucketResultHandler
result.setIBMSSEKPEnabled(response.getHeaders().get(Headers.IBM_SSE_KP_ENABLED));
result.setIBMSSEKPCrk(response.getHeaders().get(Headers. IBM_SSE_KP_CUSTOMER_ROOT_KEY_CRN));
Head Bucket Example
HeadBucketResult result = s3client.headBucket(headBucketRequest)
boolean KPEnabled = result.getIBMSSEKPEnabled();
String crn = result.getIBMSSEKPCUSTOMERROOTKEYCRN();

使用 Aspera 高速傳輸

透過安裝 Aspera 高速傳輸函式庫,您即可在應用程式中使用高速檔案傳輸功能。 Aspera 函式庫為閉源軟體,因此是 Object Storage SDK(採用 Apache 授權)的可選依賴項。

每一個 Aspera 高速傳送階段作業都會產生在用戶端機器上執行的個別 ascp 處理程序,以執行傳送。 請確定您的運算環境可以容許執行此處理程序。

您需要建立 S3 Client 和 IAM Token Manager 類別的實例,以初始化該功能 AsperaTransferManager。 必須 s3Client 使用 才能取得目標儲存桶 Object Storage 的 FASP 連線資訊。 必須 tokenManager 提供此 Aspera 高速傳輸 SDK 才能對 Object Storage 目標儲存桶進行身份驗證。

起始設定 AsperaTransferManager

在起始設定 AsperaTransferManager 之前,請確定您已使用 s3Client 及 tokenManager 物件。

使用 AsperaTransferManagerBuilder 建置 AsperaTransferManager 時,建議使用 TokenManager tokenManager = new DefaultTokenManager(new DelegateTokenProvider(apiKey)); 並避免使用 .withTokenManager(tokenManager)。

除非您預期在網路中看到大量的雜訊或封包流失,否則使用 Aspera 高速傳送的單一階段作業不會有多大的好處。 因此,我們需要告知 AsperaTransferManager 使用 AsperaConfig 類別,以使用多個階段作業。 此機制將傳輸過程拆分為多個並行會話,各會話傳送的資料塊大小由閾值決定。

使用多個階段作業的一般配置應該是:

  • 2500 MBps 目標率
  • 100 MB 臨界值(此為大部分應用程式的建議值)
AsperaTransferManagerConfig transferConfig = new AsperaTransferManagerConfig()
    .withMultiSession(true);
AsperaConfig asperaConfig = new AsperaConfig()
    .withTargetRateMbps(2500L)
    .withMultiSessionThresholdMb(100);
TokenManager tokenManager = new DefaultTokenManager(new DelegateTokenProvider(API_KEY));
AsperaTransferManager asperaTransferMgr = new AsperaTransferManagerBuilder(API_KEY, s3Client)
    .withAsperaTransferManagerConfig(transferConfig)
    .withAsperaConfig(asperaConfig)
    .build();

在上述範例中,SDK 會大量產生足夠的階段作業,以嘗試達到目標率 2500 MBps。

或者,可以在 SDK 中明確配置階段作業管理。 在需要更精確控制網路使用率的情況下,這十分有用。

使用明確的多個階段作業的一般配置應該是:

  • 2 或 10 個階段作業
  • 100 MB 臨界值(此為大部分應用程式的建議值)
AsperaConfig asperaConfig = new AsperaConfig()
    .withMultiSession(2)
    .withMultiSessionThresholdMb(100);
TokenManager tokenManager = new DefaultTokenManager(new DelegateTokenProvider(API_KEY));
AsperaTransferManager asperaTransferMgr = new AsperaTransferManagerBuilder(API_KEY, s3Client)
    .withAsperaConfig(asperaConfig)
    .build();

為了在大多數情境下獲得最佳效能,請務必使用多個工作階段,以將建立 Aspera 高速傳輸實例所涉及的處理作業降至最低。 如果您的網路容量至少為 1 Gbps,您應該使用 10 個階段作業。 較低頻寬的網路應該使用兩個階段作業。

金鑰值

  • API_KEY - 具有「撰寫者」或「管理者」角色之使用者或服務 ID 的 API 金鑰

您需要提供一個 IAM API 金鑰,以便建立一個 AsperaTransferManager. 目前 不 支援 HMAC 認證。 如需 IAM 的相關資訊,請按一下這裡。

檔案上傳

String filePath = "<absolute-path-to-source-data>";
String bucketName = "<bucket-name>";
String itemName = "<item-name>";
// Load file
File inputFile = new File(filePath);
// Create AsperaTransferManager for FASP upload
AsperaTransferManager asperaTransferMgr = new AsperaTransferManagerBuilder(API_KEY, s3Client).build();
// Upload test file and report progress
Future<AsperaTransaction> asperaTransactionFuture = asperaTransferMgr.upload(bucketName, itemName, inputFile);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();

金鑰值

  • <bucket-name>- 您在已启用 Aspera 的 Object Storage 服务实例中,该存储桶的名称。
  • <absolute-path-to-source-data>- 將上傳至 Object Storage 的目錄與檔案名稱。
  • <item-name>- 新增至儲存桶中的新物件名稱。

檔案下載

String bucketName = "<bucket-name>";
String outputPath = "<absolute-path-to-file>";
String itemName = "<item-name>";
// Create local file
File outputFile = new File(outputPath);
outputFile.createNewFile();
// Create AsperaTransferManager for FASP download
AsperaTransferManager asperaTransferMgr = new AsperaTransferManagerBuilder(COS_API_KEY_ID, s3Client)
    .withTokenManager(tokenManager)
    .withAsperaConfig(asperaConfig)
    .build();
// Download file
Future<AsperaTransaction> asperaTransactionFuture = asperaTransferMgr.download(bucketName, itemName, outputPath);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();

金鑰值

  • <bucket-name>- 您在已启用 Aspera 的 Object Storage 服务实例中,该存储桶的名称。
  • <absolute-path-to-file>- 從 Object Storage 儲存的目錄及檔案名稱。
  • <item-name>- 儲存桶中物件的名稱。

目錄上傳

String bucketName = "<bucket-name>";
String directoryPath = "<absolute-path-to-directory-for-new-file>";
String directoryPrefix = "<virtual-directory-prefix>";
boolean includeSubDirectories = true;
// Load Directory
File inputDirectory = new File(directoryPath);
// Create AsperaTransferManager for FASP upload
AsperaTransferManager asperaTransferMgr = new AsperaTransferManagerBuilder(COS_API_KEY_ID, s3Client)
    .withTokenManager(tokenManager)
    .withAsperaConfig(asperaConfig)
    .build();
// Upload test directory
Future<AsperaTransaction> asperaTransactionFuture  = asperaTransferMgr.uploadDirectory(bucketName, directoryPrefix, inputDirectory, includeSubDirectories);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();

金鑰值

  • <bucket-name>- 您在已启用 Aspera 的 Object Storage 服务实例中,该存储桶的名称。
  • <absolute-path-to-directory>- 將上傳至 Object Storage 的檔案目錄。
  • <virtual-directory-prefix>- 上傳時將附加至每個檔案的目錄前綴名稱。 請使用空值或空字串,將檔案上傳至儲存區根目錄。

目錄下載

String bucketName = "<bucket-name>";
String directoryPath = "<absolute-path-to-directory>";
String directoryPrefix = "<virtual-directory-prefix>";
boolean includeSubDirectories = true;
// Load Directory
File outputDirectory = new File(directoryPath);
// Create AsperaTransferManager for FASP download
AsperaTransferManager asperaTransferMgr = new AsperaTransferManagerBuilder(COS_API_KEY_ID, s3Client)
    .withTokenManager(tokenManager)
    .withAsperaConfig(asperaConfig)
    .build();
// Download test directory
Future<AsperaTransaction> asperaTransactionFuture   = asperaTransferMgr.downloadDirectory(bucketName, directoryPrefix, outputDirectory, includeSubDirectories);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();

金鑰值

  • <bucket-name>- 您在已启用 Aspera 的 Object Storage 服务实例中,该存储桶的名称。
  • <absolute-path-to-directory>- 用於儲存從 Object Storage 下載的檔案的目錄。
  • <virtual-directory-prefix>- 每個待下載檔案的目錄前綴名稱。 請使用空值或空字串,以下載儲存區中的所有檔案。

在每個傳送基礎上置換階段作業配置

在每個傳送基礎上,您可以透過將 AsperaConfig 的實例傳遞至上傳及下載已置換方法,來置換多階段作業配置值。 使用 AsperaConfig,您可以指定階段作業數及每個階段作業的檔案臨界值大小下限。

String bucketName = "<bucket-name>";
String filePath = "<absolute-path-to-file>";
String itemName = "<item-name>";
// Load file
File inputFile = new File(filePath);
// Create AsperaTransferManager for FASP upload
AsperaTransferManager asperaTransferMgr = new AsperaTransferManagerBuilder(API_KEY, s3Client)
.withTokenManager(TOKEN_MANAGER)
.withAsperaConfig(asperaConfig)
.build();
// Create AsperaConfig to set number of sessions
// and file threshold per session.
AsperaConfig asperaConfig = new AsperaConfig().
withMultiSession(10).
withMultiSessionThresholdMb(100);
// Upload test file and report progress
Future<AsperaTransaction> asperaTransactionFuture  = asperaTransferMgr.upload(bucketName, itemName, inputFile, asperaConfig, null);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();

監視傳送進度

監視檔案/目錄傳送進度的最簡單方式是使用 isDone() 內容,當您的傳送完成時,會傳回 true。

Future<AsperaTransaction> asperaTransactionFuture  = asperaTransferMgr.downloadDirectory(bucketName, directoryPrefix, outputDirectory, includeSubDirectories);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();
while (!asperaTransaction.isDone()) {
    System.out.println("Directory download is in progress");
    //pause for 3 seconds
    Thread.sleep(1000 * 3);
}

您也可以透過在 上呼叫 方法 onQueue,來檢查轉帳是否已排入處理佇列 AsperaTransaction。該方法會 onQueue 傳回一個布林值,若為,則 true 表示該筆轉帳已排入佇列。

Future<AsperaTransaction> asperaTransactionFuture  = asperaTransferMgr.downloadDirectory(bucketName, directoryPrefix, outputDirectory, includeSubDirectories);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();
while (!asperaTransaction.isDone()) {
    System.out.println("Directory download is in queueing: " + asperaTransaction.onQueue());
    //pause for 3 seconds
    Thread.sleep(1000 * 3);
}

若要檢查傳送是否正在進行,請在 AsperaTransaction 中呼叫進度方法。

Future<AsperaTransaction> asperaTransactionFuture  = asperaTransferMgr.downloadDirectory(bucketName, directoryPrefix, outputDirectory, includeSubDirectories);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();
while (!asperaTransaction.isDone()) {
    System.out.println("Directory download is in progress: " + asperaTransaction.progress());
    //pause for 3 seconds
    Thread.sleep(1000 * 3);
}

預設情況下,每次傳輸都會 TransferProgress 附帶一個。 該報告會 TransferProgress 顯示已傳輸的位元組數,以及相對於總傳輸位元組數的傳輸百分比。 若要存取傳送的 TransferProgress,請在 getProgress 中使用 AsperaTransaction 方法。

Future<AsperaTransaction> asperaTransactionFuture  = asperaTransferMgr.downloadDirectory(bucketName, directoryPrefix, outputDirectory, includeSubDirectories);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();
while (!asperaTransaction.isDone()) {
    TransferProgress transferProgress = asperaTransaction.getProgress();
    //pause for 3 seconds
    Thread.sleep(1000 * 3);
}

若要報告傳送的位元組數,請在 getBytesTransferred上呼叫 TransferProgress 方法。 若要報告傳送的位元組總數傳送百分比,請在 getPercentTransferred 上呼叫 TransferProgress 方法。

Future<AsperaTransaction> asperaTransactionFuture  = asperaTransferMgr.downloadDirectory(bucketName, directoryPrefix, outputDirectory, includeSubDirectories);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();
while (!asperaTransaction.isDone()) {
    TransferProgress transferProgress = asperaTransaction.getProgress();
    System.out.println("Bytes transferred: " + transferProgress.getBytesTransferred());
    System.out.println("Percent transferred: " + transferProgress.getPercentTransferred());
    //pause for 3 seconds
    Thread.sleep(1000 * 3);
}

暫停/繼續/取消

SDK 可讓您透過 AsperaTransfer 物件的下列方法來管理檔案/目錄傳送的進度:

  • pause()
  • resume()
  • cancel()

呼叫上述任一種方法時,不會產生任何副作用。 SDK 會處理適當的清除及整理。

下列範例顯示這些方法的可能用法:

String bucketName = "<bucket-name>";
String directoryPath = "<absolute-path-to-directory>";
String directoryPrefix = "<virtual-directory-prefix>";
boolean includeSubDirectories = true;
AsperaTransferManager asperaTransferMgr = new AsperaTransferManagerBuilder(COS_API_KEY_ID, _cos)
    .withTokenManager(TOKEN_MANAGER)
    .build();
File outputDirectory = new File(directoryName);
System.out.println("Starting directory download...");
//download the directory from cloud storage
Future<AsperaTransaction> asperaTransactionFuture  = asperaTransferMgr.downloadDirectory(bucketName, directoryPrefix, outputDirectory, includeSubDirectories);
AsperaTransaction asperaTransaction = asperaTransactionFuture.get();
int pauseCount = 0;
while (!asperaTransaction.isDone()) {
    System.out.println("Directory download in progress...");
    //pause the transfer
    asperaTransfer.pause();
    //resume the transfer
    asperaTransfer.resume();
    //cancel the transfer
    asperaTransfer.cancel();
}
System.out.println("Directory download complete!");

疑難排解 Aspera 問題

**問題:**在 Linux 或 Mac OS X 上使用 Oracle JDK 的開發人員在傳送期間可能會遇到非預期且無聲自動的損毀

**原因:**原生程式碼需要它自己的信號處理程式,這可能會置換 JVM 的信號處理程式。 可能需要使用 JVM 的信號鏈結機能。

IBM® JDK 使用者或 Microsoft® Windows 使用者不受此影響。

**解決方案:**鏈結並載入 JVM 的信號鏈結程式庫。

  • 在 Linux 上尋找 libjsig.so 共用程式庫,並設定下列環境變數:

    • LD_PRELOAD=<PATH_TO_SHARED_LIB>/libjsig.so
  • 在 Mac OS X 上,尋找共用程式庫 libjsig.dylib,並設定下列環境變數:

    • DYLD_INSERT_LIBRARIES=<PATH_TO_SHARED_LIB>/libjsig.dylib
    • DYLD_FORCE_FLAT_NAMESPACE=0

請參閱 Oracle® JDK 文件,以取得有關訊號鏈結的更多資訊。

**問題:**Linux 上的 UnsatisfiedLinkError

**原因:**系統無法載入相依程式庫。 在應用程式日誌中,可能會看到下列錯誤:

libfaspmanager2.so: libawt.so: cannot open shared object file: No such file or directory

**解決方案:**設定下列環境變數:

LD_LIBRARY_PATH=<JAVA_HOME>/jre/lib/amd64/server:<JAVA_HOME>/jre/lib/amd64

更新 meta 資料

有兩種方式可更新現有物件上的 meta 資料:

  • 具有新 meta 資料及原始物件內容的 PUT 要求
  • 使用新 meta 資料來執行 COPY 要求,並指定原始物件作為副本來源

使用 PUT 更新 meta 資料

此 PUT 請求會覆寫物件的現有內容,因此必須先將其下載,再使用新的元資料重新上傳。

public static void updateMetadataPut(String bucketName, String itemName, String key, String value) throws IOException {
    System.out.printf("Updating metadata for item: %s\n", itemName);
    //retrieve the existing item to reload the contents
    S3Object item = _cos.getObject(new GetObjectRequest(bucketName, itemName));
    S3ObjectInputStream itemContents = item.getObjectContent();
    //read the contents of the item in order to set the content length and create a copy
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    int b;
    while ((b = itemContents.read()) != -1) {
        output.write(b);
    }
    int contentLength = output.size();
    InputStream itemCopy = new ByteArrayInputStream(output.toByteArray());
    //set the new metadata
    HashMap<String, String> userMetadata = new HashMap<String, String>();
    userMetadata.put(key, value);
    ObjectMetadata metadata = new ObjectMetadata();
    metadata.setContentLength(contentLength);
    metadata.setUserMetadata(userMetadata);
    PutObjectRequest req = new PutObjectRequest(bucketName, itemName, itemCopy, metadata);
    _cos.putObject(req);
    System.out.printf("Updated metadata for item %s from bucket %s\n", itemName, bucketName);
}

使用 COPY 更新 meta 資料

public static void updateMetadataCopy(String bucketName, String itemName, String key, String value) {
    System.out.printf("Updating metadata for item: %s\n", itemName);
    //set the new metadata
    HashMap<String, String> userMetadata = new HashMap<String, String>();
    userMetadata.put(key, value);
    ObjectMetadata metadata = new ObjectMetadata();
    metadata.setUserMetadata(userMetadata);
    //set the copy source to itself
    CopyObjectRequest req = new CopyObjectRequest(bucketName, itemName, bucketName, itemName);
    req.setNewObjectMetadata(metadata);
    _cos.copyObject(req);
    System.out.printf("Updated metadata for item %s from bucket %s\n", itemName, bucketName);
}

使用 Immutable Object Storage

將保護配置新增至現有儲存區

此 PUT 作業的實作使用 protection 查詢參數來設定現有儲存區的保留參數。 此作業可讓您設定或變更最短保留期間、預設值及最長保留期間。 此作業也可讓您變更儲存區的保護狀態。

在保護期間過期,並移除物件上的所有合法保留之前,無法刪除寫入受保護儲存區的物件。 除非在物件建立時提供物件特定值,否則會將儲存區的預設保留值提供給物件。 位於受保護儲存桶中、且已不再受保留政策約束(保留期限已屆滿,且該物件未受任何法律保留要求限制)的物件,一旦被覆寫,將再次受到保留政策的約束。 新的保留期間可作為物件覆寫請求的一部分提供,或將儲存桶的預設保留時間套用至該物件。

保留期間設定 的最小與最大支援值 MinimumRetention``DefaultRetention,分別 MaximumRetention 為至少 0 天,至多 365243 天(1000 年)。

public static void addProtectionConfigurationToBucket(String bucketName) {
    System.out.printf("Adding protection to bucket: %s\n", bucketName);
    BucketProtectionConfiguration newConfig = new BucketProtectionConfiguration()
        .withStatus(BucketProtectionStatus.Retention)
        .withMinimumRetentionInDays(10)
        .withDefaultRetentionInDays(100)
        .withMaximumRetentionInDays(1000);
    cos.setBucketProtection(bucketName, newConfig);
    System.out.printf("Protection added to bucket %s\n", bucketName);
}
public static void addProtectionConfigurationToBucketWithRequest(String bucketName) {
    System.out.printf("Adding protection to bucket: %s\n", bucketName);
    BucketProtectionConfiguration newConfig = new BucketProtectionConfiguration()
        .withStatus(BucketProtectionStatus.Retention)
        .withMinimumRetentionInDays(10)
        .withDefaultRetentionInDays(100)
        .withMaximumRetentionInDays(1000);
    SetBucketProtectionConfigurationRequest newRequest = new SetBucketProtectionConfigurationRequest()
        .withBucketName(bucketName)
        .withProtectionConfiguration(newConfig);
    cos.setBucketProtectionConfiguration(newRequest);
    System.out.printf("Protection added to bucket %s\n", bucketName);
}

檢查儲存區的保護

public static void getProtectionConfigurationOnBucket(String bucketName) {
    System.out.printf("Retrieving protection configuration from bucket: %s\n", bucketName;
    BucketProtectionConfiguration config = cos.getBucketProtection(bucketName);
    String status = config.getStatus();
    System.out.printf("Status: %s\n", status);
    if (!status.toUpperCase().equals("DISABLED")) {
        System.out.printf("Minimum Retention (Days): %s\n", config.getMinimumRetentionInDays());
        System.out.printf("Default Retention (Days): %s\n", config.getDefaultRetentionInDays());
        System.out.printf("Maximum Retention (Days): %s\n", config.getMaximumRetentionInDays());
    }
}

上傳受保護物件

位於受保護儲存桶中、且已不再受保留政策約束(保留期限已屆滿,且該物件未受任何法律保留要求限制)的物件,一旦被覆寫,將再次受到保留政策的約束。 新的保留期間可作為物件覆寫請求的一部分提供,或將儲存桶的預設保留時間套用至該物件。

值 類型 說明
Retention-Period 非負整數(秒) 儲存在物件上的保留期間(以秒為單位)。 除非已過保留期間中指定的時間,否則無法改寫或刪除物件。 如果指定此欄位及 Retention-Expiration-Date,則會傳回 400 錯誤。 若未指定任何一項,則採用儲存桶的週期 DefaultRetention。 零 (0) 是合法值,假設儲存區最小保留期間也為 0。
Retention-expiration-date 日期(ISO 8601 格式) 能夠合法刪除或修改物件的日期。 您只能指定此項或 Retention-Period 標頭。 若兩者皆已指定,則會傳回錯誤 400。 若未指定任何一項,則採用儲存桶的 DefaultRetention 保留期間。
Retention-legal-hold-id 字串 要套用至物件的單一合法保留。 合法保留是 Y 字元長字串。 除非已移除與物件相關聯的所有合法保留,否則無法改寫或刪除物件。
public static void putObjectAddLegalHold(String bucketName, String objectName, String fileText, String legalHoldId) {
    System.out.printf("Add legal hold %s to %s in bucket %s with a putObject operation.\n", legalHoldId, objectName, bucketName);
    InputStream newStream = new ByteArrayInputStream(fileText.getBytes(StandardCharsets.UTF_8));
    ObjectMetadata metadata = new ObjectMetadata();
    metadata.setContentLength(fileText.length());
    PutObjectRequest req = new PutObjectRequest(
        bucketName,
        objectName,
        newStream,
        metadata
    );
    req.setRetentionLegalHoldId(legalHoldId);
    cos.putObject(req);
    System.out.printf("Legal hold %s added to object %s in bucket %s\n", legalHoldId, objectName, bucketName);
}
public static void copyProtectedObject(String sourceBucketName, String sourceObjectName, String destinationBucketName, String newObjectName) {
    System.out.printf("Copy protected object %s from bucket %s to %s/%s.\n", sourceObjectName, sourceBucketName, destinationBucketName, newObjectName);
    CopyObjectRequest req = new CopyObjectRequest(
        sourceBucketName,
        sourceObjectName,
        destinationBucketName,
        newObjectName
    );
    req.setRetentionDirective(RetentionDirective.COPY);
    cos.copyObject(req);
    System.out.printf("Protected object copied from %s/%s to %s/%s\n", sourceObjectName, sourceBucketName, destinationBucketName, newObjectName);
}

延長受保護物件的保留期間

只能延長物件的保留期間。 不能從目前配置的值縮短。

保留擴充值以三種方式之一來設定:

  • 現行值再加上時間(Additional-Retention-Period 或類似方法)
  • 新擴充期間(以秒為單位)(Extend-Retention-From-Current-Time 或類似方法)
  • 物件的新保留到期日(New-Retention-Expiration-Date 或類似方法)

儲存在物件 meta 資料中的現行保留期間,會增加給定的額外時間,或以新值取代,視 extendRetention 要求中設定的參數而定。 在所有情況下,會針對現行保留期間檢查延長保留參數,而且只有在更新的保留期間大於現行保留期間時,才會接受延長的參數。

位於受保護儲存桶中、且已不再受保留政策約束(保留期限已屆滿,且該物件未受任何法律保留要求限制)的物件,一旦被覆寫,將再次受到保留政策的約束。 新的保留期間可作為物件覆寫請求的一部分提供,或將儲存桶的預設保留時間套用至該物件。

public static void extendRetentionPeriodOnObject(String bucketName, String objectName, Long additionalSeconds) {
    System.out.printf("Extend the retention period on %s in bucket %s by %s seconds.\n", objectName, bucketName, additionalSeconds);
    ExtendObjectRetentionRequest req = new ExtendObjectRetentionRequest(
        bucketName,
        objectName)
        .withAdditionalRetentionPeriod(additionalSeconds);
    cos.extendObjectRetention(req);
    System.out.printf("New retention period on %s is %s\n", objectName, additionalSeconds);
}

列出受保護物件的合法保留

此作業傳回:

  • 物件建立日期
  • 物件保留期間(秒)
  • 根據期間和建立日期計算的保留到期日
  • 合法保留的清單
  • 合法保留 ID
  • 套用合法保留時的時間戳記

如果物件沒有任何合法保留,則會傳回空的 LegalHoldSet。 如果在物件上未指定保留期間,則會傳回 404 錯誤。

public static void listLegalHoldsOnObject(String bucketName, String objectName) {
    System.out.printf("List all legal holds on object %s in bucket %s\n", objectName, bucketName);
    ListLegalHoldsResult result = cos.listLegalHolds(
        bucketName,
        objectName
    );
    System.out.printf("Legal holds on bucket %s: \n", bucketName);
    List<LegalHold> holds = result.getLegalHolds();
    for (LegalHold hold : holds) {
        System.out.printf("Legal Hold: %s", hold);
    }
}

建立代管的靜態網站

這項作業需要新增 import 陳述式:

import com.ibm.cloud.objectstorage.services.s3.model.model.BucketWebsiteConfiguration;

此作業在配置時提供下列項目,且需要正確配置的用戶端:

  • 字尾 (索引文件) 的儲存區配置
  • 金鑰的儲存區配置 (錯誤文件)
cosClient.setBucketWebsiteConfiguration("<bucket_name>", new BucketWebsiteConfiguration("index.html", "error.html"));

後續步驟

如需相關資訊,請參閱 Javadoc。 您可以在 GitHub 儲存庫中找到專案的原始碼。