低频访问、归档类型、冷归档或者深度冷归档有最低存储时长的要求。在存储不足规定时长的情况下,转换Object存储类型或提前删除Object会产生不足规定时长容量费用。为避免产生不足规定时长容量费用,您需要了解不同存储类型Object的最低存储时长计算方法,确保满足其最低存储时长后再进行转储或者删除。
存储类型与最低存储时长
存储类型 | 最低存储时长 | 计算方法 |
标准 | 无 | 不涉及 |
低频访问 | 30 | 以Object的LastModified时间开始计算 |
归档 | 60 | 以Object的LastModified时间开始计算 |
冷归档 | 180 | 以Object转储为冷归档类型的时间开始计算 |
深度冷归档 | 180 | 以Object转储为深度冷归档类型的时间开始计算 |
示例代码
以常用SDK示例代码为例获取对象元数据,并根据对象的LastModified、TransitionTime与当前时间进行比较,以判断是否满足最低存储时长的要求。
Java
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.common.utils.DateUtil;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.HeadObjectRequest;
import com.aliyuncs.exceptions.ClientException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class Demo {
public static void main(String[] args) throws ClientException {
// yourEndpoint填写Bucket所在地域对应的Endpoint。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写Bucket名称。
String bucketName = "examplebucket";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
// 指定要检查的单个对象的完整路径。
String[] objectNames = {"example.txt"};
// 存储类型与最低存储时长映射(单位:天)。
Map<String, Integer> minimumRetentionPeriod = new HashMap<>();
minimumRetentionPeriod.put("Standard", 0);
minimumRetentionPeriod.put("IA", 30);
minimumRetentionPeriod.put("Archive", 60);
minimumRetentionPeriod.put("ColdArchive", 180);
minimumRetentionPeriod.put("DeepColdArchive", 180);
for (String objectName : objectNames) {
objectName = objectName.trim();
try {
// 获取对象元数据。
HeadObjectRequest headObjectRequest = new HeadObjectRequest(bucketName, objectName);
ObjectMetadata objectMetadata = ossClient.headObject(headObjectRequest);
// 获取存储类型和最后修改时间。
String storageClass = String.valueOf(objectMetadata.getObjectStorageClass());
String lastModifiedStr = objectMetadata.getLastModified().toString();
Date lastModified = objectMetadata.getLastModified();
if ("ColdArchive".equals(storageClass) || "DeepColdArchive".equals(storageClass)) {
Object transitionTimeObj = objectMetadata.getRawMetadata().get("x-oss-transition-time");
String transitionTimeStr = String.valueOf(transitionTimeObj);
Date transitionTime = DateUtil.parseRfc822Date(transitionTimeStr);
if (transitionTime != null) {
lastModified = transitionTime;
} else {
throw new Exception("对象 '" + objectName + "' 的存储类型为:" + storageClass
+ ", x-oss-transition-time时间为" + transitionTimeStr + "。");
}
}
// 获取当前时间。
Date currentTime = new Date();
// 计算已存储时长(天)。
long storageDuration = (currentTime.getTime() - lastModified.getTime()) / (1000 * 60 * 60 * 24);
// 打印信息。
System.out.println("对象名称: " + objectName);
System.out.println("存储类型: " + storageClass);
System.out.println("创建时间: " + lastModifiedStr);
System.out.println("已存储时长: " + storageDuration + " 天");
// 判断是否达到最低存储时长。
if (minimumRetentionPeriod.containsKey(storageClass)) {
int minRetention = minimumRetentionPeriod.get(storageClass);
if (storageDuration < minRetention) {
int daysRemaining = minRetention - (int) storageDuration;
System.out.println(objectName + " 尚未达到最低存储时长,应再存储 " + daysRemaining + " 天,提前删除会产生"
+ daysRemaining + "天的不足规定时长的容量费用。");
} else {
int daysExceeded = (int) storageDuration - minRetention;
System.out.println(objectName + " 已达到最低存储时长,超出部分为 " + daysExceeded + " 天,删除不会产生不足规定时长的容量费用。");
}
} else {
System.out.println(objectName + " 的存储类型未被识别。");
}
System.out.println("----------------------------------------"); // 分隔符
} catch (Exception e) {
e.printStackTrace();
System.out.println("获取 " + objectName + " 元数据时出现错误: " + e.getMessage());
System.out.println("----------------------------------------"); // 分隔符
}
}
// 关闭OSSClient。
ossClient.shutdown();
}
}
Python
import datetime
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', 'examplebucket')
# 指定要检查的单个对象的完整路径。
object_names = ['example.txt']
# 存储类型与最低存储时长映射(单位:天)。
minimum_retention_period = {
'Standard': 0,
'IA': 30,
'Archive': 60,
'ColdArchive': 180,
'DeepColdArchive': 180
}
for object_name in object_names:
object_name = object_name.strip()
try:
# 通过head_object方法获取对象的全部元数据。
object_info = bucket.head_object(object_name)
# 获取存储类型和最后修改时间。
storage_class = object_info.headers['x-oss-storage-class']
last_modified = object_info.headers['Last-Modified']
# 将最后修改时间转换为datetime对象。
last_modified_time = datetime.datetime.strptime(last_modified, '%a, %d %b %Y %H:%M:%S GMT')
transition_time_str = object_info.headers.get('x-oss-transition-time')
transition_time = None
if storage_class == 'ColdArchive' or storage_class == 'DeepColdArchive':
if transition_time_str:
last_modified_time = datetime.datetime.strptime(transition_time_str, "%a, %d %b %Y %H:%M:%S %Z")
else:
raise Exception(f"对象 '{object_name}' 的存储类型为:{storage_class}, x-oss-transition-time时间为{transition_time_str}。")
# 获取当前时间。
current_time = datetime.datetime.now()
# 计算已存储时长(天)。
storage_duration = (current_time - last_modified_time).days
# 打印信息。
print(f"对象名称: {object_name}")
print(f"存储类型: {storage_class}")
print(f"创建时间: {last_modified}")
print(f"已存储时长: {storage_duration} 天")
# 判断是否达到最低存储时长。
if storage_class in minimum_retention_period:
min_retention = minimum_retention_period[storage_class]
if storage_duration < min_retention:
days_remaining = min_retention - storage_duration
print(f"{object_name} 尚未达到最低存储时长,应再存储 {days_remaining} 天,提前删除会产生{days_remaining}天的不足规定时长的容量费用。")
else:
days_exceeded = storage_duration - min_retention
print(f"{object_name} 已达到最低存储时长,超出部分为 {days_exceeded} 天,删除不会产生不足规定时长的容量费用。")
else:
print(f"{object_name} 的存储类型未被识别。")
print("-" * 40) # 分隔符
except Exception as e:
print(f"获取 {object_name} 元数据时出现错误: {str(e)}")
print("-" * 40) # 分隔符
Node.js
const OSS = require("ali-oss");
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
const config = {
accessKeyId: process.env.OSS_ACCESS_KEY_ID,
accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,
// region填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
region: "oss-cn-hangzhou",
// 填写Bucket名称。
bucket: "examplebucket",
};
const client = new OSS(config);
// 存储类型与最低存储时长映射(单位:天)。
const minimum_retention_period = {
Standard: 0,
IA: 30,
Archive: 60,
ColdArchive: 180,
DeepColdArchive: 180,
};
// 计算时间相差天数。
function getDays(date1, date2) {
if (!(date1 instanceof Date) || !(date2 instanceof Date)) {
throw new Error("需要传递有效的Date对象");
}
const timestamp1 = date1.getTime();
const timestamp2 = date2.getTime();
const diffInMilliseconds = Math.abs(timestamp2 - timestamp1);
const diffInDays = diffInMilliseconds / (1000 * 60 * 60 * 24);
return Math.round(diffInDays);
}
// 指定要检查的单个对象的完整路径。
const object_names = ["example.jpg"];
(async () => {
for (const object_name of object_names) {
try {
// 通过head方法获取对象的全部元数据。
const object_info = await client.head(object_name);
const { headers } = object_info.res;
// 获取存储类型和最后修改时间。
const storage_class = headers["x-oss-storage-class"];
const last_modified = headers["last-modified"];
let last_modified_time = new Date(last_modified);
const transition_time_str = headers["x-oss-transition-time"];
if (["ColdArchive", "DeepColdArchive"].includes(storage_class)) {
if (transition_time_str)
last_modified_time = new Date(transition_time_str);
else {
const errorStr = `对象 '${object_name}' 的存储类型为:${storage_class}, x-oss-transition-time时间为${transition_time_str}。通过生命周期转到冷归档和深度冷归档的文件,才会有x-oss-transition-time`;
throw new Error(errorStr);
}
}
const current_time = new Date(); // 获取当前时间。
const storage_duration = getDays(current_time, last_modified_time); // 计算已存储时长(天)。
// 打印信息。
console.log(`对象名称: ${object_name}`);
console.log(`存储类型: ${storage_class}`);
console.log(`创建时间: ${last_modified}`);
console.log(`已存储时长: ${storage_duration} 天`);
// 判断是否达到最低存储时长。
if (Object.keys(minimum_retention_period).includes(storage_class)) {
min_retention = minimum_retention_period[storage_class];
if (storage_duration < min_retention) {
const days_remaining = min_retention - storage_duration;
console.log(
`${object_name} 尚未达到最低存储时长,应再存储 ${days_remaining} 天,提前删除会产生${days_remaining}天的不足规定时长的容量费用。`
);
} else {
const days_exceeded = storage_duration - min_retention;
console.log(
`${object_name} 已达到最低存储时长,超出部分为 ${days_exceeded} 天,删除不会产生不足规定时长的容量费用。`
);
}
} else console.log(`${object_name} 的存储类型未被识别。`);
} catch (e) {
console.log(`获取 ${object_name} 元数据时出现错误:`, e);
}
}
})();
PHP
<?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\Core\OssException;
// 填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
$endpoint = 'http://oss-cn-hangzhou.aliyuncs.com';
// 填写存储空间名称。
$bucketName = 'examplebucket';
// 创建OssClient实例。
try {
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
$provider = new EnvironmentVariableCredentialsProvider();
$config = array(
"provider" => $provider,
"endpoint" => $endpoint,
);
$ossClient = new OssClient($config);
// 指定要检查的单个对象的完整路径。
$objectNames = ['example.txt'];
$minimumRetentionPeriod = [
'Standard' => 0,
'IA' => 30,
'Archive' => 60,
'ColdArchive' => 180,
'DeepColdArchive' => 180,
];
foreach ($objectNames as $objectName) {
$objectName = trim($objectName);
try {
// 通过headObject方法获取对象的全部元数据。
$objectInfo = $ossClient->getObjectMeta($bucketName, $objectName);
// 获取存储类型和最后修改时间。
$storageClass = $objectInfo['x-oss-storage-class'];
$lastModified = $objectInfo['last-modified'];
// 将最后修改时间转换为时间戳。
$lastModifiedTime = strtotime($lastModified);
if (in_array($storageClass, array("ColdArchive", "DeepColdArchive")) && isset($objectInfo["x-oss-transition-time"])) {
$lastModifiedTime = strtotime($objectInfo["x-oss-transition-time"]);
}
// 获取当前时间。
$currentTime = time();
// 计算已存储时长(天)。
$storageDuration = floor(($currentTime - $lastModifiedTime) / (60 * 60 * 24));
// 打印信息。
echo "对象名称: $objectName\n";
echo "存储类型: $storageClass\n";
echo "创建时间: $lastModified\n";
echo "已存储时长: $storageDuration 天\n";
// 判断是否达到最低存储时长。
if (isset($minimumRetentionPeriod[$storageClass])) {
$minRetention = $minimumRetentionPeriod[$storageClass];
if ($storageDuration < $minRetention) {
$daysRemaining = $minRetention - $storageDuration;
echo "$objectName 尚未达到最低存储时长,应再存储 $daysRemaining 天,提前删除会产生 $daysRemaining 天的不足规定时长的容量费用。\n";
} else {
$daysExceeded = $storageDuration - $minRetention;
echo "$objectName 已达到最低存储时长,超出部分为 $daysExceeded 天,删除不会产生不足规定时长的容量费用。\n";
}
} else {
echo "$objectName 的存储类型未被识别。\n";
}
echo str_repeat("-", 40) . "\n"; // 分隔符
} catch (OssException $e) {
echo "获取 $objectName 元数据时出现错误: " . $e->getMessage() . "\n";
echo str_repeat("-", 40) . "\n"; // 分隔符
}
}
} catch (OssException $e) {
printf(__FUNCTION__ . ": FAILED\n");
printf($e->getMessage() . "\n");
return;
}
Go
package main
import (
"context"
"fmt"
"log"
"net/http"
"strings"
"time"
"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)
func main() {
cfg := oss.LoadDefaultConfig().
WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
WithRegion("cn-hangzhou").
WithEndpoint("https://oss-cn-hangzhou.aliyuncs.com")
client := oss.NewClient(cfg)
// 指定要检查的单个对象的完整路径。
objectNames := []string{"example.txt"}
minimumRetentionPeriod := map[string]int{
"Standard": 0,
"IA": 30,
"Archive": 60,
"ColdArchive": 180,
"DeepColdArchive": 180,
}
// 填写Bucket名称。
bucketName := "examplebucket"
for _, objectName := range objectNames {
objectName = strings.Trim(objectName, " ")
objectInfo, err := client.HeadObject(context.TODO(), &oss.HeadObjectRequest{
Bucket: oss.Ptr(bucketName),
Key: oss.Ptr(objectName),
})
if err != nil {
log.Printf("获取 %s 元数据时出现错误: %v\n", objectName, err)
continue
}
storageClass := objectInfo.StorageClass
currentTime := time.Now().Unix()
storageDuration := (currentTime - objectInfo.LastModified.Unix()) / 60 / 60 / 24
if *storageClass == "ColdArchive" || *storageClass == "DeepColdArchive" {
if objectInfo.Headers.Get("x-oss-transition-time") != "" {
transitionTime, err := time.Parse(http.TimeFormat, objectInfo.Headers.Get("x-oss-transition-time"))
if err != nil {
fmt.Printf("Failed to parse %s x-oss-transition-time: %v\n", objectName, err)
continue
}
storageDuration = (currentTime - transitionTime.Unix()) / 60 / 60 / 24
}
}
fmt.Printf("对象名称: %s\n", objectName)
fmt.Printf("存储类型: %s\n", *storageClass)
fmt.Printf("创建时间: %s\n", *objectInfo.LastModified)
fmt.Printf("已存储时长: %d 天\n", storageDuration)
if minimumRetentionPeriod[*storageClass] != 0 {
minRetention := minimumRetentionPeriod[*storageClass]
daysRemaining := minRetention - int(storageDuration)
fmt.Printf("%s 尚未达到最低存储时长,应再存储 %d 天,提前删除会产生 %d 天的不足规定时长的容量费用。\n", objectName, daysRemaining, daysRemaining)
} else {
fmt.Printf("%s 的存储类型未被识别。\n", objectName)
}
}
}
更多参考
以上示例代码演示通过head_object方法获取单个对象的存储类型,并根据对象的LastModified、TransitionTime与当前时间进行比较,以判断是否满足最低存储时长的要求。如果涉及获取多个对象,可以使用GetBucket (ListObjects)、ListObjectVersions(GetBucketVersions)、ListBucketInventory接口。