开启版本控制下Object的操作

重要

本文中含有需要您注意的重要提示信息,忽略该信息可能对您的业务造成影响,请务必仔细阅读。

存储空间(Bucket)开启版本控制后,OSS会为Bucket中所有文件(Object)的每个版本指定唯一的ID值,且Bucket中现有Object的内容和权限保持不变。开启版本控制后,还能够防止意外覆盖或者删除Object ,并允许查询和恢复Object的历史版本。

注意事项

当您在已开启版本控制的Bucket中进行上传文件、列举文件、下载文件、删除文件、恢复文件等操作时,有如下注意事项:

  • 对于已开启版本控制的Bucket中的Object,OSS会维护一个当前版本Object以及零个或零个以上历史版本Object。

  • 如果在Bucket开启版本控制前上传了Object,则OSSObject的版本ID值置为null。

  • 本文图示中的版本ID均以简短版本ID代替。

关于版本控制的更多信息,请参见版本控制介绍

上传文件

在已开启版本控制的Bucket中上传Object时,OSS会为这些上传的Object自动添加唯一的版本ID。

说明

PutObject、PostObject、CopyObject 、MultipartUpload等操作都会为新生成的Object自动添加唯一的版本ID。

通过PUT操作上传Object(key=example.jpg)时,OSS为该Object指定了唯一的版本号(ID=111111),如下图所示。

通过PUT操作第一次上传同名Object(key=example.jpg)时,原始Object版本(ID=111111)作为历史版本,生成的新版本(ID=222222)将作为当前版本保存在Bucket中。当再次上传同名Object时,原始Object版本(包括ID=111111以及ID=222222)将作为历史版本,而生成的新版本(ID=333333)则作为当前版本保存在Bucket中,如下图所示。

使用OSS控制台

  1. 登录OSS管理控制台

  2. 单击Bucket 列表,然后单击目标Bucket名称。

  3. 在左侧导航栏,选择文件管理>文件列表

  4. 文件列表页面,单击上传文件

  5. 上传文件面板,按如下说明配置各项参数。

    1. 设置基础选项。

      参数

      说明

      上传到

      设置文件上传到目标Bucket后的存储路径。

      • 当前目录:将文件上传到当前目录。

      • 指定目录:将文件上传到指定目录,您需要输入目录名称。如果输入的目录不存在,OSS将自动创建对应的文件目录并将文件上传到该目录中。

        目录命名规范如下:

        • 请使用符合要求的UTF-8字符;长度必须在1~254字符之间。

        • 不允许以正斜线(/)或反斜线(\)开头。

        • 不允许出现连续的正斜线(/)。

        • 不允许出现名为 .. 的目录。

      文件ACL

      设置文件读写权限ACL。

      • 继承Bucket:以Bucket读写权限为准。

      • 私有(推荐):只有文件Owner拥有该文件的读写权限,其他用户没有权限操作该文件。

      • 公共读:文件Owner拥有该文件的读写权限,其他用户(包括匿名访问者)都可以对文件进行访问,这有可能造成您数据的外泄以及费用激增,请谨慎操作。

      • 公共读写:任何用户(包括匿名访问者)都可以对文件进行访问,并且向该文件写入数据。这有可能造成您数据的外泄以及费用激增。如果被人恶意写入违法信息还可能会侵害您的合法权益。除特殊场景外,不建议您为文件配置公共读写权限。

      关于文件ACL的更多信息,请参见设置Object ACL

      待上传文件

      选择您需要上传的文件或文件夹。

      您可以单击扫描文件扫描文件夹选择本地文件或文件夹,或者直接拖拽目标文件或文件夹到待上传文件区域。

      如果上传文件夹中包含了无需上传的文件,请单击目标文件操作列的移除将其移出文件列表。

      重要
      • 在未开启版本控制的Bucket中上传文件时,如果上传的文件与已有文件同名,则覆盖已有文件。

      • 在已开启版本控制的Bucket中上传文件时,如果上传的文件与已有文件同名,则上传的文件将成为最新版本,已有文件将成为历史版本。

    2. 可选:单击高级选项右侧的image.png图标,设置文件存储类型、加密方式等高级选项。

      参数

      说明

      存储类型

      设置文件存储类型。 取值范围如下:

      • 继承Bucket(默认):以Bucket存储类型为准。

      • 标准存储提供高可靠、高可用、高性能的对象存储服务,能够支持频繁的数据访问。适用于各种社交、分享类的图片、音视频应用、大型网站、大数据分析等业务场景。

      • 低频访问存储提供高持久性、较低存储成本的对象存储服务。有最小计量单位(64 KB)和最低存储时间(30天)的要求。支持数据实时访问,访问数据时会产生数据取回费用。适用于较低访问频率(平均每月访问频率12次)的业务场景。

      • 归档存储提供高持久性、极低存储成本的对象存储服务。有最小计量单位(64 KB)和最低存储时间(60天)的要求。数据需解冻(约1分钟)后访问,会产生数据解冻费用。如果开启归档直读,无需解冻就可以访问数据,会产生数据直读取回费用。适用于数据长期保存的业务场景,例如档案数据、医疗影像、科学资料、影视素材等。

      • 冷归档存储提供高持久性、比归档存储的存储成本更低的对象存储服务。有最小计量单位(64 KB)和最低存储时间(180天)的要求。数据需解冻后访问,解冻时间根据数据大小和选择的解冻模式决定,解冻会产生数据取回费用以及取回请求费用。适用于需要超长时间存放的冷数据,例如因合规要求需要长期留存的数据、大数据及人工智能领域长期积累的原始数据、影视行业长期留存的媒体资源、在线教育行业的归档视频等业务场景。

      • 深度冷归档存储提供高持久性、比冷归档存储成本更低的对象存储服务。有最小计量单位(64 KB)和最低存储时间(180天)的要求。数据需解冻后访问,解冻时间根据数据大小和选择的解冻模式决定,解冻会产生数据取回费用以及取回请求费用。适用于需要超长时间存放的极冷数据,例如大数据及人工智能领域的原始数据的长期积累留存、媒体数据的长期保留、法规和合规性存档、磁带替换等业务场景。

      更多信息,请参见存储类型介绍

      服务端加密方式

      设置文件的服务端加密方式。 取值范围如下:

      • 继承 Bucket(默认):以Bucket的服务器端加密方式为准。

      • OSS完全托管:使用OSS托管的密钥进行加密。OSS会为每个Object使用不同的密钥进行加密,作为额外的保护,OSS会使用主密钥对加密密钥本身进行加密。

      • KMS:使用KMS默认托管的CMK或指定CMK ID进行加解密操作。

        使用KMS加密方式前,需要开通KMS服务。具体操作,请参见开通密钥管理服务

        KMS对应的加密密钥说明如下:

        加密密钥格式为<alias>(CMK ID)。其中<alias>为用户主密钥的别名,CMK ID为用户主密钥ID。取值范围如下:

        • alias/acs/oss(CMK ID):使用默认托管的CMK生成不同的密钥来加密不同的Object,并且在Object被下载时自动解密。

        • alias/<cmkname>(CMK ID):使用指定的CMK生成不同的密钥来加密不同的Object,并将加密ObjectCMK ID记录到Object的元数据中,具有解密权限的用户下载Object时会自动解密。其中<cmkname>为创建密钥时配置的主密钥可选标识。

          使用指定的CMK ID前,您需要在KMS管理控制台创建一个与Bucket处于相同地域的普通密钥或外部密钥。具体操作,请参见创建密钥

      • 加密算法可选择AES256SM4加密算法。

      用户自定义元数据

      用于为Object添加描述信息。您可以添加多条自定义元数据(User Meta),但所有的自定义元数据总大小不能超过8 KB。添加自定义元数据时,要求参数以x-oss-meta-为前缀,并为参数赋值,例如x-oss-meta-location:hangzhou

    3. 单击上传文件

      此时,您可以在任务列表面板的上传列表页签查看各个文件的上传进度。

使用阿里云SDK

以下仅列举常见SDK在已开启版本控制的Bucket中简单上传文件的代码示例。关于其他SDK简单上传的代码示例,请参见SDK简介

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import java.io.ByteArrayInputStream;

public class Demo {
    public static void main(String[] args) throws Exception {
        // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填写Bucket名称,例如examplebucket。
        String bucketName = "examplebucket";
        // 填写Object的完整路径。Object完整路径中不能包含Bucket名称。
        String objectName = "exampledir/object";

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        try {
            // 以上传字符串为例。
            String content = "Hello OSS";
            PutObjectResult result = ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content.getBytes()));
            // 查看此次上传Object的VersionId。
            System.out.println("result.versionid: " + result.getVersionId());
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}
<?php
if (is_file(__DIR__ . '/../autoload.php')) {
    require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
    require_once __DIR__ . '/../vendor/autoload.php';
}

use OSS\Credentials\EnvironmentVariableCredentialsProvider;
use OSS\OssClient;
use OSS\CoreOssException;

// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
$provider = new EnvironmentVariableCredentialsProvider();
// Endpoint以杭州为例,其它Region请按实际情况填写。
$endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
$bucket= "<yourBucketName>";
// 填写不包含Bucket名称在内的Object的完整路径,例如example/test.txt。
$object = "<yourObjectName>";
$content = "hello world";

$config = array(
        "provider" => $provider,
        "endpoint" => $endpoint,
    );
    $ossClient = new OssClient($config);

try {
    // 在受版本控制的Bucket中上传Object。
    $ret = $ossClient->putObject($bucket, $object, $content);

    // 查看Object的版本信息。
    print("versionId:" .$ret[OssClient::OSS_HEADER_VERSION_ID]);
} catch (OssException $e) {
    printf(__FUNCTION__ . ": FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}

print(__FUNCTION__ . ": OK" . "\n");
const OSS = require('ali-oss');

const client = new OSS({
  // yourregion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
  region: 'yourregion',
  // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
  accessKeyId: process.env.OSS_ACCESS_KEY_ID,
  accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,
  // yourbucketname填写存储空间名称。
  bucket: 'yourbucketname'
});

async function put() {
  const result = await client.put('fileName', path.normalize('D:\\localpath\\examplefile.txt');
  console.log(result.res.headers['x-oss-version-id']); // 查看此次上传object的版本ID。
}
put();
# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
# 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider())
# 填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
# yourBucketName填写存储空间名称。
bucket = oss2.Bucket(auth, 'https://oss-cn-hangzhou.aliyuncs.com', 'yourBucketName')

# 上传文件。
result = bucket.put_object('yourObjectName', 'content of object')
# HTTP返回码。
print('http response code: {0}'.format(result.status))
# 查看本次上传Object的版本ID。
print('put object version:', result.versionid)
using System.Text;
using Aliyun.OSS;
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
var endpoint = "yourEndpoint";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
// 填写Bucket名称,例如examplebucket。
var bucketName = "examplebucket";
// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
var objectName = "exampleobject.txt";
var objectContent = "More than just cloud.";
// 创建OSSClient实例。
var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
try
{
    byte[] binaryData = Encoding.ASCII.GetBytes(objectContent);
    MemoryStream requestContent = new MemoryStream(binaryData);
    // 上传文件。
    var result = client.PutObject(bucketName, objectName, requestContent);
    Console.WriteLine("Put object succeeded versionid : {0}", result.VersionId);
}
catch (Exception ex)
{
    Console.WriteLine("Put object failed, {0}", ex.Message);
}
package main

import (
  "fmt"
  "net/http"
  "os"
  "strings"

  "github.com/aliyun/aliyun-oss-go-sdk/oss"
)

func main() {
    // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
    provider, err := oss.NewEnvironmentVariableCredentialsProvider()
    if err != nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }

    // 创建OSSClient实例。
    // yourEndpoint填写Bucket对应的Endpoint,以华东1(杭州)为例,填写为https://oss-cn-hangzhou.aliyuncs.com。其它Region请按实际情况填写。
    client, err := oss.New("yourEndpoint", "", "", oss.SetCredentialsProvider(&provider))
    if err != nil {
       fmt.Println("Error:", err)
       os.Exit(-1)
  }

  // yourBucketName填写存储空间名称。
  bucket, err := client.Bucket("yourBucketName")
  if err != nil {
    fmt.Println("Error:", err)
    os.Exit(-1)
  }

  var retHeader http.Header
  // 上传字符串。用oss.GetResponseHeader获取返回header。
  // yourObjectName填写不包含Bucket名称在内的Object的完整路径。
  err = bucket.PutObject("yourObjectName", strings.NewReader("yourObjectValue"), oss.GetResponseHeader(&retHeader))
  if err != nil {
    fmt.Println("Error:", err)
    os.Exit(-1)
  }
  // 打印x-oss-version-id。
  fmt.Println("x-oss-version-id:", oss.GetVersionId(retHeader))
}
#include <alibabacloud/oss/OssClient.h>
using namespace AlibabaCloud::OSS;

int main(void)
{
    /* 初始化OSS账号信息。*/
            
    /* yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
    std::string Endpoint = "yourEndpoint";
    /* 填写Bucket名称,例如examplebucket。*/
    std::string BucketName = "examplebucket";
    /* 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。*/
    std::string ObjectName = "exampledir/exampleobject.txt";

    /* 初始化网络等资源。*/
    InitializeSdk();

    ClientConfiguration conf;
    /* 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/
    auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>();
    OssClient client(Endpoint, credentialsProvider, conf);
    std::shared_ptr<std::iostream> content = std::make_shared<std::stringstream>();
    *content << "test cpp sdk";
    PutObjectRequest request(BucketName, ObjectName, content);

    /* 上传文件。*/
    auto outcome = client.PutObject(request);

    if (outcome.isSuccess()) {
        std::cout << "versionid:" << outcome.result().VersionId() << std::endl;
    }
    else {
        /* 异常处理。*/
        std::cout << "PutObject fail" <<
        ",code:" << outcome.error().Code() <<
        ",message:" << outcome.error().Message() <<
        ",requestId:" << outcome.error().RequestId() << std::endl;
        return -1;
    }

    /* 释放网络等资源。*/
    ShutdownSdk();
    return 0;
}

使用命令行工具ossutil

关于使用ossutil在已开启版本控制的Bucket中简单上传文件的具体操作, 请参见cp(上传文件)

使用REST API

如果您的程序自定义要求较高,您可以直接发起REST API请求。直接发起REST API请求需要手动编写代码计算签名。更多信息,请参见PutObject

列举文件

在已开启版本控制的Bucket中,您可以使用GetBucketVersions(ListObjectVersions)接口获取Object的所有版本信息,包括删除标记(Delete Marker)。

  • GetBucketVersions(ListObjectVersions)不同的是,GetBucket(ListObject)接口仅返回Object的当前版本,且当前版本不为删除标记。

  • 单个GetBucketVersions(ListObjectVersions)请求最多返回1000个版本Object。您可以通过发送多次请求来获取Object的所有版本。

    例如,如果Bucket中包含两个Key(如example.jpgphoto.jpg),且第一个Key(example.jpg)有900个版本,第二个Key(photo.jpg)有500个版本,则单个请求将先按照Key的字母序,再按照版本的新旧顺序依次列举example.jpg的所有900个版本以及photo.jpg100个版本。

如下图所示,在开启了版本控制的Bucket中,调用GetBucketVersions(ListObjectVersions)接口时,返回了Bucket中所有Object的所有版本,包含当前版本为删除标记的Object ;调用GetBucket(ListObject)接口时,则仅返回Object的当前版本,且当前版本不能为删除标记,因此仅返回当前版本ID444444Object。

使用OSS控制台

  1. 登录OSS管理控制台

  2. 单击Bucket 列表,然后单击目标Bucket名称。

    当前页面将分页显示该Bucket中所有Object的当前版本,且当前版本不能为删除标记。如果您需要查看该Bucket中包含删除标记在内所有Object的所有版本,请在文件列表页面单击历史版本右侧的显示

使用阿里云SDK

以下仅列举常见SDK在已开启版本控制的Bucket中列举文件的代码示例。关于其他SDK列举文件的代码示例,请参见SDK简介

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;

public class Demo {
    public static void main(String[] args) throws Exception {
        // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填写Bucket名称,例如examplebucket。
        String bucketName = "examplebucket";

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        try {
            // 列举包括删除标记在内的所有Object的版本信息。
            String nextKeyMarker = null;
            String nextVersionMarker = null;
            VersionListing versionListing = null;
            do {
                ListVersionsRequest listVersionsRequest = new ListVersionsRequest()
                        .withBucketName(bucketName)
                        .withKeyMarker(nextKeyMarker)
                        .withVersionIdMarker(nextVersionMarker);

                versionListing = ossClient.listVersions(listVersionsRequest);
                for (OSSVersionSummary ossVersion : versionListing.getVersionSummaries()) {
                    System.out.println("key name: " + ossVersion.getKey());
                    System.out.println("versionid: " + ossVersion.getVersionId());
                    System.out.println("Is latest: " + ossVersion.isLatest());
                    System.out.println("Is delete marker: " + ossVersion.isDeleteMarker());
                }

                nextKeyMarker = versionListing.getNextKeyMarker();
                nextVersionMarker = versionListing.getNextVersionIdMarker();
            } while (versionListing.isTruncated());
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}
<?php
if (is_file(__DIR__ . '/../autoload.php')) {
    require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
    require_once __DIR__ . '/../vendor/autoload.php';
}

use OSS\Credentials\EnvironmentVariableCredentialsProvider;
use OSS\OssClient;
use OSS\CoreOssException;

// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 
$provider = new EnvironmentVariableCredentialsProvider();
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
$endpoint = "yourEndpoint";
// 填写Bucket名称,例如examplebucket。
$bucket= "examplebucket";

$config = array(
        "provider" => $provider,
        "endpoint" => $endpoint,
    );
    $ossClient = new OssClient($config);

try{
    $option = array(
        OssClient::OSS_KEY_MARKER => null,
        OssClient::OSS_VERSION_ID_MARKER => null
    );
    $bool = true;
    while ($bool){
        $result = $ossClient->listObjectVersions($bucket,$option);
        // 查看Object的版本信息。
        foreach ($result->getObjectVersionList() as $key => $info){
            printf("key name: {$info->getKey()}\n");
            printf("versionid: {$info->getVersionId()}\n");
            printf("Is latest: {$info->getIsLatest()}\n\n");
        }

        // 查看删除标记的版本信息。
        foreach ($result->getDeleteMarkerList() as $key => $info){
            printf("del_maker key name: {$info->getKey()}\n");
            printf("del_maker versionid: {$info->getVersionId()}\n");
            printf("del_maker Is latest: {$info->getIsLatest()}\n\n");
        }

        if($result->getIsTruncated() === 'true'){
            $option[OssClient::OSS_KEY_MARKER] = $result->getNextKeyMarker();
        $option[OssClient::OSS_VERSION_ID_MARKER] = $result->getNextVersionIdMarker();
        }else{
            $bool = false;
        }
    }
} catch(OssException $e) {
    printf($e->getMessage() . "\n");
    return;
}
const OSS = require("ali-oss");

const client = new OSS({
  // yourregion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
  region: 'yourregion',
  // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
  accessKeyId: process.env.OSS_ACCESS_KEY_ID,
  accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,
  // 填写存储空间名称。
  bucket: 'yourbucketname'
});

// 列举包括删除标记在内的所有Object的版本信息。
async function getObjectVersions() {
  let nextKeyMarker = null;
  let nextVersionMarker = null;
  let versionListing = null;
  do {
    versionListing = await client.getBucketVersions({
      keyMarker: nextKeyMarker,
      versionIdMarker: nextVersionMarker,
    });

    versionListing.objects.forEach((o) => {
      console.log(`${o.name}, ${o.versionId}`);
    });
    versionListing.deleteMarker.forEach((o) => {
      console.log(`${o.name}, ${o.versionId}`);
    });

    nextKeyMarker = versionListing.NextKeyMarker;
    nextVersionMarker = versionListing.NextVersionIdMarker;
  } while (versionListing.isTruncated);
}

getObjectVersions();
# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
# 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider())
# 填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
# yourBucketName填写存储空间名称。
bucket = oss2.Bucket(auth, 'https://oss-cn-hangzhou.aliyuncs.com', 'yourBucketName')

# 开启Bucket版本控制后,调用list_object_versions接口返回不同版本的Object信息。
# 列举Bucket中包括删除标记(Delete Marker)在内的所有Object的版本信息。
result = bucket.list_object_versions()

# 列举所有Object的版本信息。
next_key_marker = None
next_versionid_marker = None
while True:
    result = bucket.list_object_versions(key_marker=next_key_marker, versionid_marker=next_versionid_marker)

    # 查看列举Object的版本信息。
    for version_info in result.versions:
        print('version_info.versionid:', version_info.versionid)
        print('version_info.key:', version_info.key)
        print('version_info.is_latest:', version_info.is_latest)

    # 查看列举删除标记的版本信息。
    for del_maker_Info in result.delete_marker:
        print('del_maker.key:', del_maker_Info.key)
        print('del_maker.versionid:', del_maker_Info.versionid)
        print('del_maker.is_latest:', del_maker_Info.is_latest)

    is_truncated = result.is_truncated

    # 查看列举结果是否完整。如果结果不完整,则继续罗列。如果结果已完整,则退出循环。
    if is_truncated:
        next_key_marker = result.next_key_marker
        next_versionid_marker = result.next_versionid_marker
    else:
        break
package main

import (
    "fmt"
    "os"
    "github.com/aliyun/aliyun-oss-go-sdk/oss"
)

func HandleError(err error) {
    fmt.Println("Error:", err)
    os.Exit(-1)
}

func main() {
    // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
    provider, err := oss.NewEnvironmentVariableCredentialsProvider()
    if err != nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }
    // 创建OSSClient实例。
    // yourEndpoint填写Bucket对应的Endpoint,以华东1(杭州)为例,填写为https://oss-cn-hangzhou.aliyuncs.com。其它Region请按实际情况填写。
    client, err := oss.New("yourEndpoint", "", "", oss.SetCredentialsProvider(&provider))
    if err != nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }

    // 填写Bucket名称。
    bucketName := "examplebucket"
    bucket,err := client.Bucket(bucketName)
    if err != nil {
        HandleError(err)
    }

    // 列举包括删除标记在内的所有Object。
    keyMarker := oss.KeyMarker("")
    // VersionIdMarker与KeyMarker参数一同使用,以指定列举的起点。
    versionIdMarker := oss.VersionIdMarker("")
    for {
        lor, err := bucket.ListObjectVersions(keyMarker,versionIdMarker)
        if err != nil {
            HandleError(err)
        }

        // 查看Object的版本信息。
        for _, dirName := range lor.ObjectVersions{
            fmt.Println("Versionid:",dirName.VersionId)
            fmt.Println("Key:",dirName.Key)
            fmt.Println("Is Latest",dirName.IsLatest)
        }
        // 查看删除标记的版本信息。
         for _, marker  := range lor.ObjectDeleteMarkers {
            fmt.Println(marker.VersionId)
            fmt.Println(marker.Key)
        }
        // 查看列举结果是否完整。如果结果不完整,则继续列举。如果结果已完整,则退出循环。
        keyMarker = oss.KeyMarker(lor.NextKeyMarker)
        versionIdMarker = oss.VersionIdMarker(lor.NextVersionIdMarker)
        if !lor.IsTruncated {
            break
        }
    }
}

使用命令行工具ossutil

关于在已开启版本控制的Bucket中列举文件的具体操作,请参见列举Object

使用REST API

如果您的程序自定义要求较高,您可以直接发起REST API请求。直接发起REST API请求需要手动编写代码计算签名。更多信息,请参见ListObjectVersions(GetBucketVersions)

下载文件

您可以在已开启版本控制的Bucket中下载当前版本或指定版本的Object。

通过GET请求下载Object时,如果未指定Object的版本ID,默认情况下返回Object的当前版本。如下图所示返回Object的当前版本(ID=333333)。

如果当前版本为删除标记(Delete Marker),在执行GET操作时,OSS会返回404 Not Found。

如果要下载指定的Object版本,则通过GET请求下载Object时需要指定其版本ID ,如下图所示获取指定版本ID222222Object。

使用OSS控制台

  1. 登录OSS管理控制台

  2. 单击Bucket 列表,然后单击目标Bucket名称。

  3. 在左侧导航栏,选择文件管理>文件列表

  4. 文件列表页面,单击历史版本右侧的显示

  5. 单击指定版本的Object,在弹出的面板单击文件URL右侧的下载

使用阿里云SDK

以下仅列举常见SDK在已开启版本控制的Bucket中下载文件的代码示例。关于其他SDK下载文件的代码示例,请参见SDK简介

说明

Python示例为Python2版本。

<?php
if (is_file(__DIR__ . '/../autoload.php')) {
    require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
    require_once __DIR__ . '/../vendor/autoload.php';
}

use OSS\OssClient;
use OSS\Core\OssException;

// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。 
$accessKeyId = getenv("OSS_ACCESS_KEY_ID"); 
$accessKeySecret = getenv("OSS_ACCESS_KEY_SECRET");
// Endpoint以杭州为例,其它Region请按实际情况填写。
$endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
$bucket= "<yourBucketName>";
// 填写不包含Bucket名称在内的Object的完整路径,例如example/test.txt。
$object = "<yourObjectName>";
// 指定Object的版本ID。
$versionId = "<yourObjectVersionId>";

$ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);

try{
    // 下载指定版本ID的Object。
    $content = $ossClient->getObject($bucket, $object, array(OssClient::OSS_VERSION_ID => $versionId));
    print($content);
} catch(OssException $e) {
    printf(__FUNCTION__ . ": FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}

print(__FUNCTION__ . ": OK" . "\n");          
const OSS = require('ali-oss');

const client = new OSS({
  // yourregion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
  region: 'yourregion',
  // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
  accessKeyId: process.env.OSS_ACCESS_KEY_ID,
  accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,
  // yourbucketname填写存储空间名称。
  bucket: 'yourbucketname'
});

async function get() {
  // 文件名称。
  const result = await client.get('filename', {    
      // 查看下载文件的版本ID。
      versionId: 'versionid',
  });
  console.log(result.content);
}
get();
# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
# 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider())
# 填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
# yourBucketName填写存储空间名称。
bucket = oss2.Bucket(auth, 'https://oss-cn-hangzhou.aliyuncs.com', 'yourBucketName')

# 下载指定版本的Object。
params = dict()
params['versionId'] = '<yourObjectVersionId>'
object_stream = bucket.get_object('<yourObjectName>', params=params)

# 读取下载的Object内容。
read_content = object_stream.read()
print('get object content:', read_content)
# 查看本次下载的object的版本ID。
print('get object versionid:', object_stream.versionid)

# 由于get_object接口返回的是一个stream流,需要执行read()后才能计算出返回Object数据的CRC checksum,因此需要在调用该接口后做CRC校验。
if object_stream.client_crc != object_stream.server_crc:
   print("The CRC checksum between client and server is inconsistent!")
package main

import (
  "fmt"
  "net/http"
  "os"  

  "github.com/aliyun/aliyun-oss-go-sdk/oss"
)

func main() {
    /// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
    provider, err := oss.NewEnvironmentVariableCredentialsProvider()
    if err != nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }

    // 创建OSSClient实例。
    // yourEndpoint填写Bucket对应的Endpoint,以华东1(杭州)为例,填写为https://oss-cn-hangzhou.aliyuncs.com。其它Region请按实际情况填写。
    client, err := oss.New("yourEndpoint", "", "", oss.SetCredentialsProvider(&provider))
    if err != nil {
      fmt.Println("Error:", err)
      os.Exit(-1)
  }

  // yourBucketName填写存储空间名称。
  bucket, err := client.Bucket("<yourBucketName>")
  if err != nil {
    fmt.Println("Error:", err)
    os.Exit(-1)
  }

  var retHeader http.Header
  // 下载yourObjectVersionId版本的文件到缓存。
  // yourObjectName填写不包含Bucket名称在内的Object的完整路径。
  _, err = bucket.GetObject("youObjectName", oss.VersionId("yourObjectVersionId"), oss.GetResponseHeader(&retHeader))
  if err != nil {
    fmt.Println("Error:", err)
    os.Exit(-1)
  }
  // 打印x-oss-version-id。
  fmt.Println("x-oss-version-id:",  oss.GetVersionId(retHeader))
}
#include <alibabacloud/oss/OssClient.h>
using namespace AlibabaCloud::OSS;

int main(void)
{
    /* 初始化OSS账号信息。*/
            
    /* yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
    std::string Endpoint = "yourEndpoint";
    /* 填写Bucket名称,例如examplebucket。*/
    std::string BucketName = "examplebucket";
    /* 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。*/
    std::string ObjectName = "exampledir/exampleobject.txt";

    /* 初始化网络等资源。*/
    InitializeSdk();

    ClientConfiguration conf;
    /* 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/
    auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>();
    OssClient client(Endpoint, credentialsProvider, conf);

    /* 获取文件到本地内存。*/
    GetObjectRequest request(BucketName, ObjectName);
    request.setVersionId("yourObjectVersionId");
    auto outcome = client.GetObject(request);
    if (outcome.isSuccess()) {
        std::cout << "getObjectToBuffer" << " success, Content-Length:" << outcome.result().Metadata().ContentLength() << std::endl;
        /* 读取下载的Object内容。*/
        std::string content;
        *(outcome.result().Content()) >> content;
        std::cout << "getObjectToBuffer" << "content:" << content << std::endl;
        /* 查看本次下载Object的版本ID。*/
        std::cout << "versionid:" << outcome.result().VersionId() << std::endl;
    }
    else {
            /* 异常处理。*/
            std::cout << "getObjectToBuffer fail" <<
        ",code:" << outcome.error().Code() <<
        ",message:" << outcome.error().Message() <<
        ",requestId:" << outcome.error().RequestId() << std::endl;
        return -1;
    }

    /* 释放网络等资源。*/
    ShutdownSdk();
    return 0;
}

使用命令行工具ossutil

关于使用ossutil在已开启版本控制的Bucket中下载文件的具体操作,请参见cp(下载文件)

使用REST API

如果您的程序自定义要求较高,您可以直接发起REST API请求。直接发起REST API请求需要手动编写代码计算签名。更多信息,请参见GetObject

删除文件

开启版本控制后,您可以通过指定Object版本ID或者配置LifecycleObject永久删除。如果删除Object时未指定版本ID,则Bucket中将插入一个删除标记(Delete Marker)作为当前版本。

重要
  • 开启版本控制后,如果删除Object时未指定版本ID,默认不会删除Object的当前版本以及历史版本。

  • 同一个Bucket请勿同时开通OSS-HDFS服务和版本控制。

    如果某个Bucket已同时开通OSS-HDFS服务和版本控制,可能导致OSS-HDFS服务异常。为保证OSS-HDFS服务的稳定性,您需要尽快暂停版本控制,同时配置生命周期规则清理删除标记。

    具体操作,请参见同时开通OSS-HDFS服务和版本控制的Bucket如何处理?

此外,您还可以在已开启版本控制的Bucket中通过生命周期规则的Expiration元素指定Object当前版本过期,还可以通过NoncurrentVersionExpiration元素永久删除非当前版本Object,对于这两种元素的详细说明如下:

  • Expiration元素应用于当前Object版本,OSS通过添加删除标记将当前版本作为非当前版本保留,而不是删除当前版本Object,然后删除标记将成为Object的当前版本。

  • NoncurrentVersionExpiration元素适用于非当前版本Object,OSS会永久删除这些Object版本,且无法恢复永久删除的Object。

关于版本控制结合生命周期的更多信息,请参见生命周期配置元素

以下分别说明在未指定版本ID以及指定版本ID的情况下,执行DELETE操作时Object的删除行为。

  • 如果未指定Object的版本ID,则OSS会插入一个删除标记作为当前版本,该删除标记也会有相应的唯一版本ID,但没有相关数据和ACL等,如下图所示(当前版本为删除标记,且版本ID=444444)。

  • 如果指定了Object的版本ID,则永久删除该指定版本的Object,如下图所示(即删除版本ID=333333Object)。

使用OSS控制台

为了减少存储费用,建议您及时删除不再需要的历史版本Object。

警告

历史版本Object被删除后无法恢复,请谨慎操作。

  1. 登录OSS管理控制台

  2. 单击Bucket 列表,然后单击目标Bucket名称。

  3. 在左侧导航栏,选择文件管理>文件列表

  4. 文件列表页面,单击历史版本右侧的显示

  5. 找到不再需要的历史版本Object,根据实际选择相应操作。

    • 如果要删除的历史版本Object为删除标记,请直接单击操作列的彻底删除

    • 如果要删除的历史版本Object不为删除标记,请将鼠标移动到文件操作列的image.png图标上单击彻底删除

    您也可以批量选中待删除的历史版本,单击页面下方的彻底删除

  6. 单击确定

    您也可以通过配置生命周期规则,定期自动删除历史版本Object。更多信息,请参见生命周期规则介绍

使用阿里云SDK

以下仅列举常见SDK在已开启版本控制的Bucket中删除指定版本文件的代码示例。关于其他SDK删除指定版本文件的代码示例,请参见SDK简介

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;

public class Demo {
    public static void main(String[] args) throws Exception {
        // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填写Bucket名称,例如examplebucket。
        String bucketName = "examplebucket";
        // 填写Object的完整路径。Object完整路径中不能包含Bucket名称。
        String objectName = "exampledir/object";
        String versionId  = "CAEQMxiBgICAof2D0BYiIDJhMGE3N2M1YTI1NDQzOGY5NTkyNTI3MGYyMzJm****";

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        try {
            // 删除指定版本的Object。
            ossClient.deleteVersion(bucketName, objectName , versionId);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}
<?php
if (is_file(__DIR__ . '/../autoload.php')) {
    require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
    require_once __DIR__ . '/../vendor/autoload.php';
}

use OSS\Credentials\EnvironmentVariableCredentialsProvider;
use OSS\OssClient;
use OSS\CoreOssException;

// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
$provider = new EnvironmentVariableCredentialsProvider();
// Endpoint以杭州为例,其它Region请按实际情况填写。
$endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
$bucket= "<yourBucketName>";
// 填写不包含Bucket名称在内的Object的完整路径,例如example/test.txt。
$object = "<yourObjectName>";
$versionId = "<yourObjectVersionId>";

$config = array(
        "provider" => $provider,
        "endpoint" => $endpoint,
    );
    $ossClient = new OssClient($config);

try{
    // 删除指定versionId的Object。
    $ossClient->deleteObject($bucket, $object, array(OssClient::OSS_VERSION_ID => $versionId));
} catch(OssException $e) {
    printf(__FUNCTION__ . ": FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}

print(__FUNCTION__ . ": OK" . "\n");        
const OSS = require("ali-oss");

const client = new OSS({
  // yourregion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
  region: 'yourregion',
  // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
  accessKeyId: process.env.OSS_ACCESS_KEY_ID,
  accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,
  // 填写存储空间名称。
  bucket: 'yourbucketname'
});

// 指定Object的versionId。
const versionId = "versionId";
// 指定Object。
const objectName = "exampleobject.txt";
async function deleteVersionObject() {
  const result = await client.delete(objectName, {
    versionId,
  });
  console.log(result);
}

deleteVersionObject();
# -*- coding: utf-8 -*-
import os
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
# 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider())
# 填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
# yourBucketName填写存储空间名称。
bucket = oss2.Bucket(auth, 'https://oss-cn-hangzhou.aliyuncs.com', 'yourBucketName')
# yourObjectName填写不包含Bucket名称在内的Object的完整路径,例如example/test.txt。
object_name = 'yourObjectName'

# 指定Object的versionId,也可以是删除标记的versionId。
params = dict()
params['versionId'] = 'yourObjectVersionIdOrDeleteMarkerVersionId'

# 删除指定versionId的Object或指定versionId的删除标记关联的Object。
result = bucket.delete_object(object_name, params=params)
print("delete object name: ", object_name)
# 如果指定的是Object的versionId,则返回的delete_marker为None且返回的versionId为指定Object的versionId。
# 如果指定的是删除标记的versionId,则返回的delete_marker为True且返回的versionId为指定删除标记的versionId。
if result.delete_marker:
    print("delete del-marker versionid: ",result.versionid)
else:
    print("delete object versionid:", result.versionid)
using Aliyun.OSS;
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
var endpoint = "yourEndpoint";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
// 填写Bucket名称,例如examplebucket。
var bucketName = "examplebucket";
// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
var objectName = "exampledir/exampleobject.txt";
// 填写Object的版本ID或删除标记的版本ID。
var versionid = "yourObjectVersionidOrDelMarkerVersionid";
// 创建OSSClient实例。
var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
try
{
    // 指定Object的versionId,也可以是删除标记的versionId。
    var request = new DeleteObjectRequest(bucketName, objectName)
    {
        VersionId = versionid
    };
    client.DeleteObject(request);
    Console.WriteLine("Delete object succeeded");
}
catch (Exception ex)
{
    Console.WriteLine("Delete object failed. {0}", ex.Message);
}
package main

import (
  "fmt"
  "os"

  "github.com/aliyun/aliyun-oss-go-sdk/oss"
)

func main() {
    /// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
    provider, err := oss.NewEnvironmentVariableCredentialsProvider()
    if err != nil {
        fmt.Println("Error:", err)
        os.Exit(-1)
    }

    // 创建OSSClient实例。
    // yourEndpoint填写Bucket对应的Endpoint,以华东1(杭州)为例,填写为https://oss-cn-hangzhou.aliyuncs.com。其它Region请按实际情况填写。
    client, err := oss.New("yourEndpoint", "", "", oss.SetCredentialsProvider(&provider))
    if err != nil {
       fmt.Println("Error:", err)
       os.Exit(-1)
  }

  // yourBucketName填写存储空间名称。
  bucket, err := client.Bucket("yourBucketName")
  if err != nil {
    fmt.Println("Error:", err)
    os.Exit(-1)
  }
  // youObjectName填写不包含Bucket名称在内的Object的完整路径。
  // yourObjectVersionId填写Object的versionId。指定后,将彻底删除该versionId的Object。
  err = bucket.DeleteObject("youObjectName", oss.VersionId("yourObjectVersionId"))
  if err != nil {
    fmt.Println("Error:", err)
    os.Exit(-1)
  }
}
#include <alibabacloud/oss/OssClient.h>
using namespace AlibabaCloud::OSS;

int main(void)
{
    /* 初始化OSS账号信息。*/
            
    /* yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
    std::string Endpoint = "yourEndpoint";
    /* 填写Bucket名称,例如examplebucket。*/
    std::string BucketName = "examplebucket";
    /* 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。*/
    std::string ObjectName = "exampledir/exampleobject.txt";

    /* 初始化网络等资源。*/
    InitializeSdk();

    ClientConfiguration conf;
    /* 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/
    auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>();
    OssClient client(Endpoint, credentialsProvider, conf);

    /* 删除指定versionId的Object或指定versionId的删除标记关联的Object。*/
    auto outcome = client.DeleteObject(DeleteObjectRequest(BucketName, ObjectName, "yourObjectVersionIdOrDeleteMarkerVersionId"));
    /* 如果指定的是Object的versionId,则返回的delete_marker为None且返回的versionId为指定Object的versionId。*/
    /* 如果指定的是删除标记的versionId,则返回的delete_marker为True且返回的versionId为指定删除标记的versionId。*/
    if (!outcome.isSuccess()) {
        /* 异常处理。*/
        std::cout << "DeleteObject fail" <<
        ",code:" << outcome.error().Code() <<
        ",message:" << outcome.error().Message() <<
        ",requestId:" << outcome.error().RequestId() << std::endl;
        return -1;
    }

    /* 释放网络等资源。*/
    ShutdownSdk();
    return 0;
}

使用命令行工具ossutil

关于使用ossutil在已开启版本控制的Bucket中删除文件的具体操作, 请参见删除Object

使用REST API

如果您的程序自定义要求较高,您可以直接发起REST API请求。直接发起REST API请求需要手动编写代码计算签名。更多信息,请参见DeleteObject

恢复文件

开启版本控制后,BucketObject的所有版本都将得以保留。您可以通过恢复指定历史版本的方式,使得任意Object的历史版本成为当前版本。

您可以通过以下两种方式将Object的历史版本恢复至当前版本:

  • 通过CopyObject来恢复Object的历史版本

    复制的Object将成为该Object的当前版本,且所有Object版本都将保留。

    如下图所示,将原Object的历史版本(ID=222222)复制到同一个Bucket中,OSS将为该Object生成新的版本(ID=444444),并将其置为该Object的当前版本。因此,该Object同时具有历史版本(ID=222222)以及当前版本(ID=444444)。

  • 通过删除Object的当前版本来恢复Object的历史版本

    如下图所示,当您通过DELETE versionId的方式永久删除当前Object版本(ID=222222)后, 下一个历史版本(ID=111111)成为了该Object的当前版本。

重要

由于Object的当前版本删除后无法恢复,建议您通过CopyObject的方式来恢复Object的历史版本。

使用OSS控制台

  1. 登录OSS管理控制台

  2. 单击Bucket 列表,然后单击目标Bucket名称。

  3. 在左侧导航栏,选择文件管理>文件列表

  4. 文件列表页面,单击历史版本右侧的显示

  5. 将指定历史版本的Object恢复为当前版本。

    重要

    同一个Object仅允许恢复其中的某个历史版本,且该历史版本不能为删除标记。

    • 恢复单个Object

      单击目标历史版本操作列的恢复

    • 恢复多个Object

      选中目标历史版本,单击页面下方的恢复后,在弹出的对话框,单击确定

使用阿里云SDK

以下仅列举常见SDK在已开启版本控制的Bucket中拷贝指定版本文件的代码示例。关于其他SDK拷贝指定版本文件的代码示例,请参见SDK简介

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;

public class Demo {
    public static void main(String[] args) throws Exception {
        // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填写源Bucket名称。
        String sourceBucketName = "srcexamplebucket";
        // 填写源Object的完整路径。Object完整路径中不能包含Bucket名称。
        String sourceObjectName = "srcexampleobject.txt";
        // 填写与源Bucket处于同一地域的目标Bucket名称。
        String destinationBucketName = "desexamplebucket";
        // 填写目标Object的完整路径。Object完整路径中不能包含Bucket名称。
        String destinationObjectName = "desexampleobject.txt";
        String versionId  = "CAEQMxiBgICAof2D0BYiIDJhMGE3N2M1YTI1NDQzOGY5NTkyNTI3MGYyMzJm****";

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        try {
            CopyObjectRequest copyObjectRequest = new CopyObjectRequest(sourceBucketName, sourceObjectName, destinationBucketName, destinationObjectName);
            copyObjectRequest.setSourceVersionId(versionId);
            CopyObjectResult copyObjectResult = ossClient.copyObject(copyObjectRequest);
            System.out.println("ETag: " + copyObjectResult.getETag() + " LastModified: " + copyObjectResult.getLastModified());
            System.out.println("dest object versionid: " + copyObjectResult.getVersionId());
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}
<?php
if (is_file(__DIR__ . '/../autoload.php')) {
    require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
    require_once __DIR__ . '/../vendor/autoload.php';
}

use OSS\Credentials\EnvironmentVariableCredentialsProvider;
use OSS\OssClient;
use OSS\CoreOssException;

// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
$provider = new EnvironmentVariableCredentialsProvider();
// Endpoint以杭州为例,其它Region请按实际情况填写。
$endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
$bucket= "<yourBucketName>";
// 填写不包含Bucket名称在内的Object的完整路径,例如example/test.txt。
$object = "<yourObjectName>";
$versionId = "<yourObjectVersionId>";
$to_bucket = $bucket;
$to_object = $object . '.copy';

$config = array(
        "provider" => $provider,
        "endpoint" => $endpoint,
    );
    $ossClient = new OssClient($config);

try{
    // 拷贝指定版本的Object。
    $ret = $ossClient->copyObject($bucket, $object, $to_bucket, $to_object, array(OssClient::OSS_VERSION_ID => $versionId));
    print("versionId:" .$ret['x-oss-version-id']);
} catch(OssException $e) {
    printf(__FUNCTION__ . ": FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}

print(__FUNCTION__ . ": OK" . "\n");    
            
const OSS = require('ali-oss');

const client = new OSS({
  // yourregion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
  region: 'yourregion',
  // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
  accessKeyId: process.env.OSS_ACCESS_KEY_ID,
  accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,
  // yourbucketname填写存储空间名称。
  bucket: 'yourbucketname'
});

// 指定拷贝源Object的versionId。
const versionId = 'versionId';
// 指定拷贝源Object。
const srcObject = 'srcObject.txt';
// 指定拷贝源Bucket。
const srcBucket = 'srcBucket;
// 指定拷贝目标Object。
const targetObject = 'targetObject.txt';
async function Copy() {
  try {
    const result = await client.copy(targetObject, srcObject, srcBucket, {
      meta: {
        versionId: versionId
      }
    });

    console.log(result);
  } catch (error) {
    console.error(error);
  }
}

Copy()
# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider

# 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider())
# 填写源Bucket名称,例如srcexamplebucket。
src_bucket_name = 'srcexamplebucket'
# 填写与源Bucket处于同一地域的目标Bucket名称,例如destexamplebucket。
# 当在同一Bucket内拷贝文件时,请确保源Bucket名称和目标Bucket名称相同。
dest_bucket_name = 'destexamplebucket'
# yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
bucket = oss2.Bucket(auth, 'https://oss-cn-hangzhou.aliyuncs.com', dest_bucket_name)

# 填写源Object完整路径,完整路径中不能包含Bucket名称,例如srcexampledir/exampleobject.txt。
src_object_name = 'srcexampledir/exampleobject.txt'
# 填写目标Object完整路径,完整路径中不能包含Bucket名称,例如destexampledir/exampleobject.txt。
dest_object_name = 'destexampledir/exampleobject.txt'
# 填写Object的版本ID。
versionId = 'CAEQMxiBgICAof2D0BYiIDJhMGE3N2M1YTI1NDQzOGY5NTkyNTI3MGYyMzJm****'

# 拷贝指定版本的文件。
params = dict()
params['versionId'] = versionId

# 从源Bucket中拷贝一个Object到目标Bucket。
result = bucket.copy_object(src_bucket_name, src_object_name, dest_object_name, params=params)
# 查看返回结果的状态,如果返回值为200时,表示执行成功。
print('result.status:', result.status)
using Aliyun.OSS;
using Aliyun.OSS.Common;
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
var endpoint = "yourEndpoint";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
// 填写源Bucket名称。
var sourceBucket = "yourSourceBucketName";
// 填写源Object的完整路径。Object完整路径中不能包含Bucket名称。
var sourceObject = "yourSourceObjectName";
// 填写与源Bucket处于同一地域的目标Bucket名称。
var targetBucket = "yourDestBucketName";
// 填写目标Object的完整路径。Object完整路径中不能包含Bucket名称。
var targetObject = "yourDestObjectName";
// 填写Object的版本ID。
var versionid = "yourArchiveObjectVersionid";
// 创建OssClient实例。
var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
try
{
    var metadata = new ObjectMetadata();
    metadata.AddHeader("mk1", "mv1");
    metadata.AddHeader("mk2", "mv2");
    var req = new CopyObjectRequest(sourceBucket, sourceObject, targetBucket, targetObject)
    {
        // 如果NewObjectMetadata为null,则为COPY模式(即拷贝源文件的元数据),非null则为REPLACE模式(即覆盖源文件的元数据)。
        NewObjectMetadata = metadata, 
        // 指定Object的版本ID。
        SourceVersionId = versionid
    };
    // 拷贝文件。
    var result = client.CopyObject(req);
    Console.WriteLine("Copy object succeeded, vesionid:{0}", result.VersionId);
}
catch (OssException ex)
{
    Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID: {2} \tHostID: {3}",
        ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
}
catch (Exception ex)
{
    Console.WriteLine("Failed with error info: {0}", ex.Message);
}
#include <alibabacloud/oss/OssClient.h>
using namespace AlibabaCloud::OSS;

int main(void)
{
    /* 初始化OSS账号信息。*/
            
    /* 填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
    std::string Endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
    /* 填写源Bucket名称,例如srcexamplebucket。*/
    std::string SourceBucketName = "srcexamplebucket";
    /* 填写与源Bucket处于同一地域的目标Bucket名称,例如destbucket。*/
    std::string CopyBucketName = "destbucket";
    /* 填写源Object的完整路径,完整路径中不能包含Bucket名称,例如srcdir/scrobject.txt。*/
    std::string SourceObjectName = "srcdir/scrobject.txt";
    /* 填写目标Object的完整路径,完整路径中不能包含Bucket名称,例如destdir/destobject.txt。*/
    std::string CopyObjectName = "destdir/destobject.txt";


    /* 初始化网络等资源。*/
    InitializeSdk();

    ClientConfiguration conf;
    /* 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/
    auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>();
    OssClient client(Endpoint, credentialsProvider, conf);

    CopyObjectRequest request(CopyBucketName, CopyObjectName);
    request.setCopySource(SourceBucketName, SourceObjectName);
    /* 填写源Object的版本ID。*/
    request.setVersionId("yourSourceObjectVersionId");

    /* 拷贝指定版本的Object。*/
    auto outcome = client.CopyObject(request);

    if (outcome.isSuccess()) {
        std::cout << "versionid:" << outcome.result().VersionId() << std::endl;
    }
    else {
        /* 异常处理。*/
        std::cout << "CopyObject fail" <<
        ",code:" << outcome.error().Code() <<
        ",message:" << outcome.error().Message() <<
        ",requestId:" << outcome.error().RequestId() << std::endl;
        return -1;
    }

    /* 释放网络等资源。*/
    ShutdownSdk();
    return 0;
}

使用命令行工具ossutil

关于使用ossutil在已开启版本控制的Bucket中将历史版本Object恢复为当前版本Object的具体操作,请参见cp(恢复文件)

使用REST API

如果您的程序自定义要求较高,您可以直接发起REST API请求。直接发起REST API请求需要手动编写代码计算签名。更多信息,请参见CopyObject