版本控制应用于桶(Bucket)中所有对象(Object)。开启桶的版本控制后,如果发生误删除或者覆盖对象的情况,您可以将对象恢复至任意的历史版本。TOS Java SDK 提供的若干接口均支持多版本功能的操作。TOS 中桶的版本控制状态包含未开启、开启(Enable)和暂停(Suspended)三种,本文介绍如何通过 TOS Java SDK 进行桶的多版本状态管理。
putObject
时,每个上传的对象都会产生一个唯一的 versionID。调用 deleteObject
时,不会删除对象,而是针对该对象生成一个带 versionID 的 deleteMarker 标记,标记该对象为已删除。在调用 getObject
、getObjectACL
、copyObject
、uploadPartCopy
、deleteObject
等接口时,您可通过可选参数 versionID 指定操作对象的具体版本。tos:PutBucketVersioning
权限。tos:GetBucketVersioning
权限。putBucketVersioning
和 getBucketVersioning
接口于 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
参数(即 prefix
为 null
)或设置 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()); } } }