You need to enable JavaScript to run this app.
导航

多版本场景(Java SDK)

最近更新时间2024.02.04 18:31:02

首次发布时间2023.01.19 14:37:15

版本控制应用于桶(Bucket)中所有对象(Object)。开启桶的版本控制后,如果发生误删除或者覆盖对象的情况,您可以将对象恢复至任意的历史版本。TOS Java SDK 提供的若干接口均支持多版本功能的操作。TOS 中桶的版本控制状态包含未开启、开启(Enable)和暂停(Suspended)三种,本文介绍如何通过 TOS Java SDK 进行桶的多版本状态管理。

多版本说明

  • 如果您的桶的多版本功能处于开启状态(Enable),调用 SDK 的 putObject 时,每个上传的对象都会产生一个唯一的 versionID。调用 deleteObject 时,不会删除对象,而是针对该对象生成一个带 versionID 的 deleteMarker 标记,标记该对象为已删除。在调用 getObjectgetObjectACLcopyObjectuploadPartCopydeleteObject 等接口时,您可通过可选参数 versionID 指定操作对象的具体版本。
  • 如果您的桶的多版本功能处于暂停状态(Suspended),新上传的对象的 versionID 为 null。现有的对象历史版本中,如果已经存在一个 null 版本,那么该历史版本将被删除,而最新版本变为 null 版本。特殊的,如果是删除对象,则最新版本为一个 null 版本号的 deleteMarker。
    桶的多版本可以开启,也可以暂停,但是不能回退到原始的未开启状态。

注意事项

  • 要开启或暂停桶的多版本状态,您的账号必须具备 tos:PutBucketVersioning 权限。
  • 要查询桶的多版本状态,您的账号必须具备 tos:GetBucketVersioning 权限。
  • Java SDK 的 putBucketVersioninggetBucketVersioning 接口于 2.5.0 版本新增,请升级到 2.5.0 或以上版本使用。

设置桶版本控制状态

以下代码展示如何设置桶状态为开启多版本(Enable)状态或暂停版本控制状态(Suspended)。

import com.volcengine.tos.TOSV2;
import com.volcengine.tos.TOSV2ClientBuilder;
import com.volcengine.tos.TosClientException;
import com.volcengine.tos.TosServerException;
import com.volcengine.tos.comm.common.VersioningStatusType;
import com.volcengine.tos.model.bucket.PutBucketVersioningInput;
import com.volcengine.tos.model.bucket.PutBucketVersioningOutput;

public class PutBucketVersioningExample {
    public static void main(String[] args) {
        String endpoint = "your endpoint";
        String region = "your region";
        String accessKey = System.getenv("TOS_ACCESS_KEY");
        String secretKey = System.getenv("TOS_SECRET_KEY");

        String bucketName = "bucket-example";

        TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey);

        try{
            PutBucketVersioningInput input = new PutBucketVersioningInput().setBucket(bucketName)
                    .setStatus(VersioningStatusType.VERSIONING_STATUS_ENABLED);
            PutBucketVersioningOutput output = tos.putBucketVersioning(input);
            System.out.println("putBucketVersioning succeed");
        } catch (TosClientException e) {
            // 操作失败,捕获客户端异常,一般情况是请求参数错误,此时请求并未发送
            System.out.println("putBucketVersioning failed");
            System.out.println("Message: " + e.getMessage());
            if (e.getCause() != null) {
                e.getCause().printStackTrace();
            }
        } catch (TosServerException e) {
            // 操作失败,捕获服务端异常,可以获取到从服务端返回的详细错误信息
            System.out.println("putBucketVersioning failed");
            System.out.println("StatusCode: " + e.getStatusCode());
            System.out.println("Code: " + e.getCode());
            System.out.println("Message: " + e.getMessage());
            System.out.println("RequestID: " + e.getRequestID());
        } catch (Throwable t) {
            // 作为兜底捕获其他异常,一般不会执行到这里
            System.out.println("putBucketVersioning failed");
            System.out.println("unexpected exception, message: " + t.getMessage());
        }
    }
}

获取桶的版本控制状态

以下代码展示如何获取桶的版本控制状态信息。

import com.volcengine.tos.TOSV2;
import com.volcengine.tos.TOSV2ClientBuilder;
import com.volcengine.tos.TosClientException;
import com.volcengine.tos.TosServerException;
import com.volcengine.tos.model.bucket.GetBucketVersioningInput;
import com.volcengine.tos.model.bucket.GetBucketVersioningOutput;

public class GetBucketVersioningExample {
    public static void main(String[] args) {
        String endpoint = "your endpoint";
        String region = "your region";
        String accessKey = System.getenv("TOS_ACCESS_KEY");
        String secretKey = System.getenv("TOS_SECRET_KEY");

        String bucketName = "bucket-example";

        TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey);

        try{
            GetBucketVersioningInput input = new GetBucketVersioningInput().setBucket(bucketName);
            GetBucketVersioningOutput output = tos.getBucketVersioning(input);
            System.out.println("getBucketVersioning succeed");
            System.out.println("bucket versioning status is " + output.getStatus());
        } catch (TosClientException e) {
            // 操作失败,捕获客户端异常,一般情况是请求参数错误,此时请求并未发送
            System.out.println("getBucketVersioning failed");
            System.out.println("Message: " + e.getMessage());
            if (e.getCause() != null) {
                e.getCause().printStackTrace();
            }
        } catch (TosServerException e) {
            // 操作失败,捕获服务端异常,可以获取到从服务端返回的详细错误信息
            System.out.println("getBucketVersioning failed");
            System.out.println("StatusCode: " + e.getStatusCode());
            System.out.println("Code: " + e.getCode());
            System.out.println("Message: " + e.getMessage());
            System.out.println("RequestID: " + e.getRequestID());
        } catch (Throwable t) {
            // 作为兜底捕获其他异常,一般不会执行到这里
            System.out.println("getBucketVersioning failed");
            System.out.println("unexpected exception, message: " + t.getMessage());
        }
    }
}

下载多版本对象

以下代码展示如何下载目标桶 bucket-example 中的 example_dir 目录下的 example_object.txt 文件的指定版本,并在内存中直接读取打印字符串。

import com.volcengine.tos.TOSV2;
import com.volcengine.tos.TOSV2ClientBuilder;
import com.volcengine.tos.TosClientException;
import com.volcengine.tos.TosServerException;
import com.volcengine.tos.model.object.GetObjectV2Input;
import com.volcengine.tos.model.object.GetObjectV2Output;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class GetObjectVersioningInStringExample {
    public static void main(String[] args) {
        String endpoint = "your endpoint";
        String region = "your region";
        String accessKey = System.getenv("TOS_ACCESS_KEY");
        String secretKey = System.getenv("TOS_SECRET_KEY");

        String bucketName = "bucket-example";
        // 对象名
        String objectKey = "example_dir/example_object.txt";
        // 版本号
        String versionId = "";

        TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey);

        GetObjectV2Input input = new GetObjectV2Input().setBucket(bucketName).setKey(objectKey).setVersionID(versionId);
        // 以下代码展示如何将数据下载到内存中并逐行读取打印
        try(GetObjectV2Output output = tos.getObject(input);
            BufferedReader reader = new BufferedReader(new InputStreamReader(output.getContent()))) {
            System.out.println("begin to read content in object.");
            String line = reader.readLine();
            while (line != null) {
                System.out.println(line);
                line = reader.readLine();
            }
        } catch (IOException e) {
            System.out.println("read data in object failed");
            e.printStackTrace();
        } catch (TosClientException e) {
            // 操作失败,捕获客户端异常,一般情况是请求参数错误,此时请求并未发送
            System.out.println("getObject failed");
            System.out.println("Message: " + e.getMessage());
            if (e.getCause() != null) {
                e.getCause().printStackTrace();
            }
        } catch (TosServerException e) {
            // 操作失败,捕获服务端异常,可以获取到从服务端返回的详细错误信息
            System.out.println("getObject failed");
            System.out.println("StatusCode: " + e.getStatusCode());
            System.out.println("Code: " + e.getCode());
            System.out.println("Message: " + e.getMessage());
            System.out.println("RequestID: " + e.getRequestID());
        } catch (Throwable t) {
            // 作为兜底捕获其他异常,一般不会执行到这里
            System.out.println("getObject failed");
            System.out.println("unexpected exception, message: " + t.getMessage());
        }
    }
}

列举多版本对象

关于列举多版本对象的使用方式,请参见列举多版本对象

拷贝多版本对象

以下代码展示如何拷贝指定版本的对象到目标桶 bucket-example 中的 example_dir 目录下的 example_object.txt 文件。

import com.volcengine.tos.TOSV2;
import com.volcengine.tos.TOSV2ClientBuilder;
import com.volcengine.tos.TosClientException;
import com.volcengine.tos.TosServerException;
import com.volcengine.tos.model.object.CopyObjectV2Input;
import com.volcengine.tos.model.object.CopyObjectV2Output;

public class CopyObjectVersioningExample {
    public static void main(String[] args) {
        String endpoint = "your endpoint";
        String region = "your region";
        String accessKey = System.getenv("TOS_ACCESS_KEY");
        String secretKey = System.getenv("TOS_SECRET_KEY");

        // 源桶名
        String srcBucketName = "src-bucket-example";
        // 源对象名,需保证对象存在,否则报404
        String srcObjectKey = "src_example_dir/example_object.txt";
        // 源对象版本号
        String srcObjectVersionId = "the specific version id";
        // 目的桶名
        String bucketName = "bucket-example";
        // 目的对象名,如果目的对象存在,默认会将其覆盖
        String objectKey = "dst_example_dir/example_object.txt";

        TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey);

        try{
            CopyObjectV2Input input = new CopyObjectV2Input().setBucket(bucketName).setKey(objectKey)
                    .setSrcBucket(srcBucketName).setSrcKey(srcObjectKey).setSrcVersionID(srcObjectVersionId);
//            // 如果需要设置目的对象的 ACL/storageClass 等元数据,或指定拷贝时元数据的继承/重写方式,可参考以下代码
//            ObjectMetaRequestOptions options = new ObjectMetaRequestOptions();
//            // 指定 ACL 为 private
//            options.setAclType(ACLType.ACL_PRIVATE);
//            // 指定 storageClass 为标准存储
//            options.setStorageClass(StorageClassType.STORAGE_CLASS_STANDARD);
//            input.setOptions(options);
//            // 指定限定条件,源对象的 ETag 与指定的 ETag 匹配时才拷贝,
//            // 指定的 ETag 可通过 headObject 获取,此处的 "XXX" 仅为示例,请使用正确的 ETag
//            input.setCopySourceIfMatch("XXX");
//            // 默认情况下目的对象的元数据,除了 ACL 之外,全部继承自源对象的元数据
//            // 可通过以下设置,指定拷贝时重写对象元数据,不继承源对象的元数据。
//            input.setMetadataDirective(MetadataDirectiveType.METADATA_DIRECTIVE_REPLACE);
            CopyObjectV2Output output = tos.copyObject(input);
            System.out.println("copyObject succeed, object's etag is " + output.getEtag());
            System.out.println("copyObject succeed, object's crc64 is " + output.getHashCrc64ecma());
        } catch (TosClientException e) {
            // 操作失败,捕获客户端异常,一般情况是请求参数错误,此时请求并未发送
            System.out.println("copyObject failed");
            System.out.println("Message: " + e.getMessage());
            if (e.getCause() != null) {
                e.getCause().printStackTrace();
            }
        } catch (TosServerException e) {
            // 操作失败,捕获服务端异常,可以获取到从服务端返回的详细错误信息
            System.out.println("copyObject failed");
            System.out.println("StatusCode: " + e.getStatusCode());
            System.out.println("Code: " + e.getCode());
            System.out.println("Message: " + e.getMessage());
            System.out.println("RequestID: " + e.getRequestID());
        } catch (Throwable t) {
            // 作为兜底捕获其他异常,一般不会执行到这里
            System.out.println("copyObject failed");
            System.out.println("unexpected exception, message: " + t.getMessage());
        }
    }
}

删除多版本对象

删除单个对象

关于删除单个多版本对象的操作示例,请见删除指定版本对象

删除指定前缀下的所有对象

以下代码展示如何删除目标桶 bucket-example 中的 example_dir 目录下的所有对象的所有版本。

警告

以下代码中如果不设置 prefix 参数(即 prefixnull)或设置 prefix = "" 空字符串,将会删除桶中所有对象数据,请谨慎检查使用!

import com.volcengine.tos.TOSV2;
import com.volcengine.tos.TOSV2ClientBuilder;
import com.volcengine.tos.TosClientException;
import com.volcengine.tos.TosServerException;
import com.volcengine.tos.model.object.*;

public class DeleteObjectVersioningWithPrefixExample {
    public static void main(String[] args) {
        String endpoint = "your endpoint";
        String region = "your region";
        String accessKey = System.getenv("TOS_ACCESS_KEY");
        String secretKey = System.getenv("TOS_SECRET_KEY");

        String bucketName = "bucket-example";
        String prefix = "example_dir/";

        TOSV2 tos = new TOSV2ClientBuilder().build(region, endpoint, accessKey, secretKey);

        try{
            boolean isTruncated = true;
            String keyMarker = null;
            String versionIdMarker = null;
            while (isTruncated) {
                ListObjectVersionsV2Input input = new ListObjectVersionsV2Input().setBucket(bucketName)
                        .setPrefix(prefix).setKeyMarker(keyMarker).setVersionIDMarker(versionIdMarker);
                ListObjectVersionsV2Output output = tos.listObjectVersions(input);
                if (output.getVersions() != null){
                    for (int i = 0; i < output.getVersions().size(); i++) {
                        ListedObjectVersion version = output.getVersions().get(i);
                        DeleteObjectInput deleteInput = new DeleteObjectInput().setBucket(bucketName)
                                .setKey(version.getKey()).setVersionID(version.getVersionID());
                        tos.deleteObject(deleteInput);
                        System.out.println("deleteObject succeed, deleted key is " + version);
                    }
                }
                if (output.getDeleteMarkers() != null){
                    for (int i = 0; i < output.getDeleteMarkers().size(); i++) {
                        ListedDeleteMarkerEntry deleteMarker = output.getDeleteMarkers().get(i);
                        DeleteObjectInput deleteInput = new DeleteObjectInput().setBucket(bucketName)
                                .setKey(deleteMarker.getKey()).setVersionID(deleteMarker.getVersionID());
                        tos.deleteObject(deleteInput);
                        System.out.println("deleteObject succeed, deleted key is " + deleteMarker);
                    }
                }
                isTruncated = output.isTruncated();
                keyMarker = output.getNextKeyMarker();
                versionIdMarker = output.getNextVersionIDMarker();
            }

        } catch (TosClientException e) {
            // 操作失败,捕获客户端异常,一般情况是请求参数错误,此时请求并未发送
            System.out.println("deleteObject failed");
            System.out.println("Message: " + e.getMessage());
            if (e.getCause() != null) {
                e.getCause().printStackTrace();
            }
        } catch (TosServerException e) {
            // 操作失败,捕获服务端异常,可以获取到从服务端返回的详细错误信息
            System.out.println("deleteObject failed");
            System.out.println("StatusCode: " + e.getStatusCode());
            System.out.println("Code: " + e.getCode());
            System.out.println("Message: " + e.getMessage());
            System.out.println("RequestID: " + e.getRequestID());
        } catch (Throwable t) {
            // 作为兜底捕获其他异常,一般不会执行到这里
            System.out.println("deleteObject failed");
            System.out.println("unexpected exception, message: " + t.getMessage());
        }
    }
}