归档或冷归档类型的Object需要解冻(Restore)之后才能读取。本文介绍如何解冻归档和冷归档Object。

解冻过程说明

对于归档类型或者冷归档类型的Object,如果需要读取Object,请提前解冻。归档类型Object解冻完成通常需要数分钟,冷归档类型Object根据不同解冻优先级,解冻完成通常需要数小时,请以实际解冻时间为准。

归档类型或者冷归档类型的Object在执行解冻前后的状态变换过程如下:
  1. Object初始时处于冷冻状态。
  2. 提交一次解冻请求后,Object处于解冻中状态。
  3. 服务端完成解冻任务后,Object进入解冻状态,此时您可以读取Object。
    • 归档类型Object

      对于归档类型的Object,解冻状态默认持续24小时,24小时内再次调用RestoreObject接口则解冻状态会自动延长24小时,一次解冻流程内可有效调用7次RestoreObject接口达到最长7天的解冻持续时间。您也可以通过传入解冻天数,一次调用RestoreObject接口指定最长7天的解冻持续时间。

    • 冷归档类型Object
      对于冷归档类型的Object,您可以指定解冻天数和解冻优先级,解冻天数最短为1天,最长为365天。不同解冻优先级的首字节取回时间如下:
      • 高优先级(Expedited):表示1小时内完成解冻。
      • 标准(Standard):表示2~5小时内完成解冻。如果不传入JobParameters节点,则默认为Standard。
      • 批量(Bulk):表示5~12小时内完成解冻。

      取回量参考值:平均每秒500个Object,三种解冻优先级总取回量为每天20 TB~40 TB。

  4. 解冻状态结束后,Object再次返回到冷冻状态。

注意事项

  • RestoreObject接口只针对归档或冷归档类型的Object,不适用于标准类型和低频访问类型的Object。
  • 如果针对该Object第一次调用RestoreObject接口,则返回202。
  • 如果针对该Object第一次调用RestoreObject接口,则返回202。如果已经成功调用过RestoreObject接口,且Object已完成解冻,再次调用时返回200 OK。
  • 在开启版本控制的Bucket中,Object的各个版本可以对应不同的存储类型。调用RestoreObject接口默认解冻Object当前版本,您可以通过指定versionId的方式来解冻Object指定版本。

计费说明

  • 解冻归档存储和冷归档存储类型文件会产生数据取回费用。更多信息,请参见数据处理费用
  • 归档类型Object可达到最长7天的解冻持续时间,冷归档类型Object可达到最长365天的解冻持续时间,在此期间不再重复收取数据取回费用。
  • 解冻状态结束后,Object又回到冷冻状态,再次执行解冻操作会收取数据取回费用。
  • 冷归档存储类型文件在数据解冻时会生成一份标准存储类型的文件副本用于访问。该文件在解冻时间结束前会以标准存储的存储费率计算临时存储费用。更多信息,请参见临时存储费用

使用OSS控制台

  1. 登录OSS管理控制台
  2. 单击Bucket列表,然后单击目标Bucket名称。
  3. 在左侧导航栏,选择文件管理 > 文件管理
  4. 在待解冻的目标文件右侧的操作栏下,选择more > 解冻
    • 归档存储类型Object
      • 解冻需要约1分钟时间,解冻成功后,Object变为解冻状态。
      • 解冻状态默认持续1天,您可以通过ossutil工具或SDK延长解冻时间,最多延长7天,之后文件又回到冷冻状态。
    • 冷归档存储类型Object

      解冻冷归档存储类型Object时,您需要通过副本有效期设置Object处于解冻状态的持续时间,单位为天。 此外,您还可以通过恢复模式设置解冻优先级。

      说明 华南1(深圳)地域的冷归档存储类型Object的副本有效期最大为7天,非华南1(深圳)地域的冷归档存储类型Object的副本有效期最大为365天。

      根据解冻文件的大小,实际解冻时间可能会有变化,请以实际解冻时间为准。

使用图形化管理工具ossbrowser

ossbrowser支持Object级别的操作与控制台支持的操作类似,请按照ossbrowser界面指引完成解冻文件的操作。关于如何使用ossbrowser,请参见快速使用ossbrowser

使用阿里云SDK

以下仅列举常见SDK的解冻文件的代码示例。关于其他SDK的解冻文件的代码示例,请参见SDK简介

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
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";
        // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
        String accessKeyId = "yourAccessKeyId";
        String accessKeySecret = "yourAccessKeySecret";
        // 填写Bucket名称,例如examplebucket。
        String bucketName = "examplebucket";
        // 填写不包含Bucket名称在内的归档类型Object的完整路径。
        String objectName = "exampledir/object";

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

        try {
            ObjectMetadata objectMetadata = ossClient.getObjectMetadata(bucketName, objectName);

            // 校验Object是否为归档类型Object。
            StorageClass storageClass = objectMetadata.getObjectStorageClass();
            if (storageClass == StorageClass.Archive) {
                // 解冻Object。
                ossClient.restoreObject(bucketName, objectName);

                // 等待解冻完成。
                do {
                    Thread.sleep(1000);
                    objectMetadata = ossClient.getObjectMetadata(bucketName, objectName);
                } while (!objectMetadata.isRestoreCompleted());
            }

            // 获取解冻Object。
            OSSObject ossObject = ossClient.getObject(bucketName, objectName);
            ossObject.getObjectContent().close();
        } 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\OssClient;
use OSS\Core\OssException;

// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
$accessKeyId = "yourAccessKeyId";
$accessKeySecret = "yourAccessKeySecret";
// Endpoint以华东1(杭州)为例,其他Region请按实际情况填写。
$endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 填写Bucket名称,例如examplebucket。
$bucket= "examplebucket";
// 填写不包含Bucket名称在内归档类型Object的完整路径,例如srcexampleobject.txt。
$object = "srcexampleobject.txt";

try {
    $ossClient = new OssClient($accessKeyId, $accessKeySecret, $endpoint);
    // 解冻文件。
    $ossClient->restoreObject($bucket, $object);
} 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',
  //阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
  accessKeyId: 'yourAccessKeyId',
  accessKeySecret: 'yourAccessKeySecret',
  //填写Bucket名称,例如examplebucket。
  bucket: 'examplebucket',
});

//填写待解冻的归档类型Object名称,例如exampleobject.txt。
client.restore('exampleobject.txt').then((res) => {
    console.log(res);
}).catch(err => {
    console.log(err);
})
# -*- coding: utf-8 -*-
import oss2

# 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
auth = oss2.Auth('<yourAccessKeyId>', '<yourAccessKeySecret>')
# yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
# 填写Bucket名称,例如examplebucket。
bucket = oss2.Bucket(auth, 'https://oss-cn-hangzhou.aliyuncs.com', 'examplebucket')
# 填写不包含Bucket名称在内的归档类型Object的完整路径。
objectName = 'yourObjectName'

bucket.restore_object(objectName)            
using Aliyun.OSS;
using Aliyun.OSS.Model;

// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
var endpoint = "yourEndpoint";
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
var accessKeyId = "yourAccessKeyId";
var accessKeySecret = "yourAccessKeySecret";
// 填写Bucket名称。
var bucketName = "examplebucket";
// 填写不包含Bucket名称在内的归档类型Object的完整路径。
var objectName = "yourObjectName";
// 自定义Object内容。
var objectContent = "More than just cloud.";
int maxWaitTimeInSeconds = 600;
// 创建OssClient实例。
var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
try
{
    // 创建归档存储空间。
    var bucket = client.CreateBucket(bucketName, StorageClass.Archive);
    Console.WriteLine("Create Archive bucket succeeded, {0} ", bucket.Name);
}
catch (Exception ex)
{
    Console.WriteLine("Create Archive bucket failed, {0}", ex.Message);
}
// 上传文件并设置存储类型为归档类型。
try
{
    byte[] binaryData = Encoding.ASCII.GetBytes(objectContent);
    MemoryStream requestContent = new MemoryStream(binaryData);
    client.PutObject(bucketName, objectName, requestContent);
    Console.WriteLine("Put object succeeded, {0}", objectName);
}
catch (Exception ex)
{
    Console.WriteLine("Put object failed, {0}", ex.Message);
}
var metadata = client.GetObjectMetadata(bucketName, objectName);
string storageClass = metadata.HttpMetadata["x-oss-storage-class"] as string;
if (storageClass != "Archive")
{
    Console.WriteLine("StorageClass is {0}", storageClass);
    return;
}
// 解冻归档Object。
RestoreObjectResult result = client.RestoreObject(bucketName, objectName);
Console.WriteLine("RestoreObject result HttpStatusCode : {0}", result.HttpStatusCode);
if (result.HttpStatusCode != HttpStatusCode.Accepted)
{
    throw new OssException(result.RequestId + ", " + result.HttpStatusCode + " ,");
}
while (maxWaitTimeInSeconds > 0)
{
    var meta = client.GetObjectMetadata(bucketName, objectName);
    string restoreStatus = meta.HttpMetadata["x-oss-restore"] as string;
    if (restoreStatus != null && restoreStatus.StartsWith("ongoing-request=\"false\"", StringComparison.InvariantCultureIgnoreCase))
    {
        break;
    }
    Thread.Sleep(1000);
    // 最长等待时间减少1秒。
    maxWaitTimeInSeconds--;
}
if (maxWaitTimeInSeconds == 0)
{
    Console.WriteLine("RestoreObject is timeout. ");
    throw new TimeoutException();
}
else
{
    Console.WriteLine("RestoreObject is successful. ");
}
// 解冻归档文件。
RestoreObjectRequest restore = new RestoreObjectRequest();
// 填写Bucket名称,例如examplebucket。
restore.setBucketName("examplebucket");
// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
restore.setObjectKey("exampledir/exampleobject.txt");
OSSAsyncTask task = oss.asyncRestoreObject(restore, new OSSCompletedCallback<RestoreObjectRequest,
        RestoreObjectResult>() {
    @Override
    public void onSuccess(RestoreObjectRequest request, RestoreObjectResult result) {
        OSSLog.logInfo("code::"+result.getStatusCode());

    }

    @Override
    public void onFailure(RestoreObjectRequest request, ClientException clientException,
                          ServiceException serviceException) {
        OSSLog.logError("error: "+serviceException.getRawMessage());

    }
});

task.waitUntilFinished();
package main

import (
	"fmt"
	"os"
	"strings"
	"time"

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

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

func main() {
	// 创建OSSClient实例。
	// yourEndpoint填写Bucket对应的Endpoint,以华东1(杭州)为例,填写为https://oss-cn-hangzhou.aliyuncs.com。其它Region请按实际情况填写。
	// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
	client, err := oss.New("yourEndpoint", "yourAccessKeyId", "yourAccessKeySecret")
	if err != nil {
		HandleError(err)
	}

	// 填写存储空间名称,例如examplebucket。
	bucketName := "examplebucket"
	// 填写不包含Bucket名称在内的Object的完整路径,例如exampledir/exampleobject.txt。
	objectName := "exampledir/exampleobject.txt"
	// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
	localFilename := "D:\\localpath\\examplefile.txt"

	// 创建存储空间。
	err = client.CreateBucket(bucketName, oss.StorageClass(oss.StorageArchive))
	if err != nil {
		HandleError(err)
	}
	
	archiveBucket, err := client.Bucket(bucketName)
	if err != nil {
		HandleError(err)
	}

	// 上传文件。
	var val = "More than just cloud."
	err = archiveBucket.PutObject(objectName, strings.NewReader(val))
	if err != nil {
		HandleError(err)
	}

	// 获取Object存储类型。
	meta, err := archiveBucket.GetObjectDetailedMeta(objectName)
	if err != nil {
		HandleError(err)
	}
	fmt.Println("X-Oss-Storage-Class : ", meta.Get("X-Oss-Storage-Class"))

	// 解冻归档类型Object。
	err = archiveBucket.RestoreObject(objectName)
	if err != nil {
		HandleError(err)
	}

	// 等待解冻结束。
	meta, err = archiveBucket.GetObjectDetailedMeta(objectName)
	if err != nil {
		HandleError(err)
	}
	for meta.Get("X-Oss-Restore") == "ongoing-request=\"true\"" {
		fmt.Println("x-oss-restore:" + meta.Get("X-Oss-Restore"))
		time.Sleep(10 * time.Second)
		meta, err = archiveBucket.GetObjectDetailedMeta(objectName)
		if err != nil {
			HandleError(err)
		}
	}
	fmt.Println("x-oss-restore:" + meta.Get("X-Oss-Restore"))

	// 下载已解冻的Object。
	err = archiveBucket.GetObjectToFile(objectName, localFilename)
	if err != nil {
		HandleError(err)
	}

	// 再次解冻Object,解冻状态会自动延长24小时。
	err = archiveBucket.RestoreObject(objectName)
	if err != nil {
		HandleError(err)
	}

	fmt.Println("ArchiveSample completed")
}
OSSRestoreObjectRequest *request = [OSSRestoreObjectRequest new];
// 填写Bucket名称,例如examplebucket。
request.bucketName = @"examplebucket";
// 填写不包含Bucket名称在内的Object完整路径,例如exampleobject.txt。
request.objectKey = @"exampleobject.txt";

OSSTask *restoreObjectTask = [client restoreObject:request];
[restoreObjectTask continueWithBlock:^id _Nullable(OSSTask * _Nonnull task) {
    if (!task.error) {
        NSLog(@"restore object success");
    } else {
        NSLog(@"restore object failed, error: %@", task.error);
    }
    return nil;
}];
#include <alibabacloud/oss/OssClient.h>
#include <thread>
#include <chrono>
using namespace AlibabaCloud::OSS;

int main(void)
{

    /*初始化OSS账号信息。*/
    /*阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。*/
    std::string AccessKeyId = "yourAccessKeyId";
    std::string AccessKeySecret = "yourAccessKeySecret";
    /*yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
    std::string Endpoint = "yourEndpoint";
    /*填写Bucket名称,例如examplebucket。*/
    std::string BucketName = "examplebucket";
    /*填写不包含Bucket名称在内的归档类型Object的完整路径。*/
    std::string ObjectName = "yourObjectName";

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

    ClientConfiguration conf;
    OssClient client(Endpoint, AccessKeyId, AccessKeySecret, conf);

    /*解冻归档Object。*/
    auto outcome = client.RestoreObject(BucketName, ObjectName);

    /*非归档Object不能解冻。*/
    if (!outcome.isSuccess()) {
        /*异常处理。*/
        std::cout << "RestoreObject fail" <<
        ",code:" << outcome.error().Code() <<
        ",message:" << outcome.error().Message() <<
        ",requestId:" << outcome.error().RequestId() << std::endl;
        ShutdownSdk();
        return -1;
    }

    std::string onGoingRestore("ongoing-request=\"false\"");

    int maxWaitTimeInSeconds = 600;
    while (maxWaitTimeInSeconds > 0)
    {
        auto meta = client.HeadObject(BucketName, ObjectName);

        std::string restoreStatus = meta.result().HttpMetaData()["x-oss-restore"];
        std::transform(restoreStatus.begin(), restoreStatus.end(), restoreStatus.begin(), ::tolower);
        if (!restoreStatus.empty() && 
        restoreStatus.compare(0, onGoingRestore.size(), onGoingRestore)==0) {
            std::cout << " success, restore status:" << restoreStatus << std::endl;
            /*成功解冻归档Object。*/
            break;
        }

        std::cout << " info, WaitTime:" << maxWaitTimeInSeconds
        << "; restore status:" << restoreStatus << std::endl;

        std::this_thread::sleep_for(std::chrono::seconds(10));
        maxWaitTimeInSeconds--;     
    }

    if (maxWaitTimeInSeconds == 0)
    {
        std::cout << "RestoreObject fail, TimeoutException" << std::endl;
    }

    /*释放网络等资源。*/
    ShutdownSdk();
    return 0;
}
#include "oss_api.h"
#include "aos_http_io.h"
/* yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
const char *endpoint = "yourEndpoint";
/* 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。*/
const char *access_key_id = "yourAccessKeyId";
const char *access_key_secret = "yourAccessKeySecret";
/* 填写Bucket名称,例如examplebucket。*/
const char *bucket_name = "examplebucket";
/* 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。*/
const char *object_name = "exampledir/exampleobject.txt";
const char *object_content = "More than just cloud.";
void init_options(oss_request_options_t *options)
{
    options->config = oss_config_create(options->pool);
    /* 用char*类型的字符串初始化aos_string_t类型。*/
    aos_str_set(&options->config->endpoint, endpoint);
    aos_str_set(&options->config->access_key_id, access_key_id);
    aos_str_set(&options->config->access_key_secret, access_key_secret);
    /* 是否使用了CNAME。0表示不使用。*/
    options->config->is_cname = 0;
    /* 用于设置网络相关参数,比如超时时间等。*/
    options->ctl = aos_http_controller_create(options->pool, 0);
}
int main(int argc, char *argv[])
{
    /* 在程序入口调用aos_http_io_initialize方法来初始化网络、内存等全局资源。*/
    if (aos_http_io_initialize(NULL, 0) != AOSE_OK) {
        exit(1);
    }
    /* 用于内存管理的内存池(pool),等价于apr_pool_t。其实现代码在apr库中。*/
    aos_pool_t *pool;
    /* 重新创建一个内存池,第二个参数是NULL,表示没有继承其它内存池。*/
    aos_pool_create(&pool, NULL);
    /* 创建并初始化options,该参数包括endpoint、access_key_id、acces_key_secret、is_cname、curl等全局配置信息。*/
    oss_request_options_t *oss_client_options;
    /* 在内存池中分配内存给options。*/  
    oss_client_options = oss_request_options_create(pool);
    /* 初始化Client的选项oss_client_options。*/
    init_options(oss_client_options);
    /* 初始化参数。*/
    aos_string_t bucket;
    aos_string_t object;
    aos_list_t buffer;
    oss_acl_e oss_acl = OSS_ACL_PRIVATE;
    aos_buf_t *content = NULL;
    aos_table_t *headers = NULL;
    aos_table_t *resp_headers = NULL; 
    aos_status_t *resp_status = NULL; 
    aos_str_set(&bucket, bucket_name);
    aos_str_set(&object, object_name);
    headers = aos_table_make(pool, 0);
    /* 创建归档存储空间。*/
    resp_status = oss_create_bucket_with_storage_class(oss_client_options, &bucket, oss_acl, OSS_STORAGE_CLASS_ARCHIVE, &resp_headers);
    if (aos_status_is_ok(resp_status)) {
        printf("create bucket succeeded\n");
    } else {
        printf("create bucket failed\n");
    }
    aos_list_init(&buffer);
    content = aos_buf_pack(oss_client_options->pool, object_content, strlen(object_content));
    aos_list_add_tail(&content->node, &buffer);
    /* 上传文件。*/
    resp_status = oss_put_object_from_buffer(oss_client_options, &bucket, &object, &buffer, headers, &resp_headers);
    if (aos_status_is_ok(resp_status)) {
        printf("put object from buffer succeeded\n");
    } else {
        printf("put object from buffer failed\n");      
    }    
    /* 解冻文件。*/
    do {
        headers = aos_table_make(pool, 0);
        resp_status = oss_restore_object(oss_client_options, &bucket, &object, headers, &resp_headers);
        printf("restore object resp_status->code: %d \n", resp_status->code);
        if (resp_status->code != 409) {
            break;
        } else {
            printf("restore object is already in progress, resp_status->code: %d \n", resp_status->code);
            apr_sleep(5000);
        }
    } while (1);
    /* 释放内存池,相当于释放了请求过程中各资源分配的内存。*/
    aos_pool_destroy(pool);
    /* 释放之前分配的全局资源。*/
    aos_http_io_deinitialize();
    return 0;
}

使用命令行工具ossutil

关于使用ossutil解冻归档和冷归档Object的具体操作, 请参见restore(解冻文件)

使用REST API

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

常见问题

Object是否已完成解冻?

当您对归档或冷归档类型Object提交了RestoreObject请求,并且希望了解Object的解冻操作是否完成时,您可以通过调用GetBucket (ListObjects)GetBucketV2 (ListObjectsV2)或者GetBucketVersions(ListObjectVersions)进行查看。