OSS支持使用对象标签(Object Tagging)对存储的Object进行分类,您可以针对同标签的Object设置生命周期规则、访问权限等。

背景信息

设置对象标签时,请注意以下事项:

  • 您可以在上传Object时设置对象标签,也可以对已上传Object设置对象标签。设置对象标签时,若对象已有标签,则覆盖原标签。设置对象标签的详情请参见PutObjectTagging
  • 设置对象标签时要求请求者有PutObjectTagging权限。
  • 更改标签时不会更新Object的Last‑Modified时间。
  • 标签合法字符集包括大小写字母、数字、空格和以下符号:

    +‑=._:/

对象标签使用一组键值对(Key-Value)来标记对象。对象标签的详情请参见对象标签

上传Object时添加对象标签

以下分别介绍简单上传、分片上传、追加上传以及断点续传上传场景下为上传的Object添加对象标签的示例。

  • 简单上传时添加对象标签

    以下代码用于简单上传时添加对象标签:

    using System.Text;
    using Aliyun.OSS;
    using System.Text;
    using Aliyun.OSS.Util;
    var endpoint = "<yourEndpoint>";
    var accessKeyId = "<yourAccessKeyId>";
    var accessKeySecret = "<yourAccessKeySecret>";
    var bucketName = "<yourBucketName>";
    var objectName = "<yourObjectName>";
    var objectContent = "More than just cloud.";
    
    String UrlEncodeKey(String key)
    {
    const string CharsetName = "utf-8";
    const char separator = '/';
    var segments = key.Split(separator);
    
    var encodedKey = new StringBuilder();
    encodedKey.Append(HttpUtils.EncodeUri(segments[0], CharsetName));
    for (var i = 1; i < segments.Length; i++)
        encodedKey.Append(separator).Append(HttpUtils.EncodeUri(segments[i], CharsetName));
    
        if (key.EndsWith(separator.ToString()))
        {
            // String#split ignores trailing empty strings, e.g., "a/b/" will be split as a 2-entries array,
            // so we have to append all the trailing slash to the uri.
            foreach (var ch in key)
            {
                if (ch == separator)
                    encodedKey.Append(separator);
                else
                    break;
            }
        }
    
    return encodedKey.ToString();
    }
    // 创建OssClient实例。
    var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
    try
    {
        byte[] binaryData = Encoding.ASCII.GetBytes(objectContent);
        MemoryStream requestContent = new MemoryStream(binaryData);
    
        var meta = new ObjectMetadata();
        // 在HTTP header中设置标签信息。
        string str = UrlEncodeKey("key1") + "=" + UrlEncodeKey("key1") + "&" + UrlEncodeKey("key2") + "=" + UrlEncodeKey("key2");
        meta.AddHeader("x-oss-tagging", str);
        var putRequest = new PutObjectRequest(bucketName, objectName, requestContent);
        putRequest.Metadata = meta;
    
        // 上传文件的同时对文件设置标签。
        client.PutObject(putRequest);
        Console.WriteLine("Put object succeeded");
    }
    catch (Exception ex)
    {
        Console.WriteLine("Put object failed, {0}", ex.Message);
    }
  • 分片上传时添加对象标签

    以下代码用于分片上传时添加对象标签:

    using Aliyun.OSS;
    using System.Text;
    var endpoint = "<yourEndpoint>";
    var accessKeyId = "<yourAccessKeyId>";
    var accessKeySecret = "<yourAccessKeySecret>";
    var bucketName = "<yourBucketName>";
    var objectName = "<yourObjectName>";
    var localFilename = "<yourLocalFilename>";
    
    String UrlEncodeKey(String key)
    {
    const string CharsetName = "utf-8";
    const char separator = '/';
    var segments = key.Split(separator);
    
    var encodedKey = new StringBuilder();
    encodedKey.Append(HttpUtils.EncodeUri(segments[0], CharsetName));
    for (var i = 1; i < segments.Length; i++)
        encodedKey.Append(separator).Append(HttpUtils.EncodeUri(segments[i], CharsetName));
    
        if (key.EndsWith(separator.ToString()))
        {
            // String#split ignores trailing empty strings, e.g., "a/b/" will be split as a 2-entries array,
            // so we have to append all the trailing slash to the uri.
            foreach (var ch in key)
            {
                if (ch == separator)
                    encodedKey.Append(separator);
                else
                    break;
            }
        }
    
    return encodedKey.ToString();
    }
    
    // 创建OssClient实例。
    var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
    // 初始化分片上传。
    var uploadId = "";
    try
    {
        // 设置上传Object及所属存储空间的名称。您可以在InitiateMultipartUploadRequest中设置ObjectMeta,但不必指定ContentLength。
        var request = new InitiateMultipartUploadRequest(bucketName, objectName);
    
        var meta = new ObjectMetadata();
        // 在HTTP header中设置标签信息。
        string str = UrlEncodeKey("key1") + "=" + UrlEncodeKey("key1") + "&" + UrlEncodeKey("key2") + "=" + UrlEncodeKey("key2");
        meta.AddHeader("x-oss-tagging", str);
        request.Metadata = meta;
    
        var result = client.InitiateMultipartUpload(request);
        uploadId = result.UploadId;
        // 打印UploadId。
        Console.WriteLine("Init multi part upload succeeded");
        Console.WriteLine("Upload Id:{0}", result.UploadId);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Init multi part upload failed, {0}", ex.Message);
    }
    // 计算分片总数。
    var partSize = 100 * 1024;
    var fi = new FileInfo(localFilename);
    var fileSize = fi.Length;
    var partCount = fileSize / partSize;
    if (fileSize % partSize != 0)
    {
        partCount++;
    }
    // 开始分片上传。partETags是保存partETag的列表,OSS收到您提交的分片列表后,会逐一验证每个分片数据的有效性。当所有的数据分片通过验证后,OSS会将这些分片组合成一个完整的文件。
    var partETags = new List<PartETag>();
    try
    {
        using (var fs = File.Open(localFilename, FileMode.Open))
        {
            for (var i = 0; i < partCount; i++)
            {
                var skipBytes = (long)partSize * i;
                // 定位到本次上传的起始位置。
                fs.Seek(skipBytes, 0);
                // 计算本次上传的分片大小,最后一个分片为剩余的数据大小。
                var size = (partSize < fileSize - skipBytes) ? partSize : (fileSize - skipBytes);
                var request = new UploadPartRequest(bucketName, objectName, uploadId)
                {
                    InputStream = fs,
                    PartSize = size,
                    PartNumber = i + 1
                };
                // 调用UploadPart接口上传分片,返回结果中包含了分片的ETag值。
                var result = client.UploadPart(request);
                partETags.Add(result.PartETag);
                Console.WriteLine("finish {0}/{1}", partETags.Count, partCount);
            }
            Console.WriteLine("Put multi part upload succeeded");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("Put multi part upload failed, {0}", ex.Message);
    }
    // 完成分片上传。
    try
    {
        var completeMultipartUploadRequest = new CompleteMultipartUploadRequest(bucketName, objectName, uploadId);
        foreach (var partETag in partETags)
        {
            completeMultipartUploadRequest.PartETags.Add(partETag);
        }
        var result = client.CompleteMultipartUpload(completeMultipartUploadRequest);
        Console.WriteLine("complete multi part succeeded");
    }
    catch (Exception ex)
    {
        Console.WriteLine("complete multi part failed, {0}", ex.Message);
    }
  • 追加上传时添加对象标签

    以下代码用于追加上传时添加对象标签:

    using Aliyun.OSS;
    using System.Text;
    var endpoint = "<yourEndpoint>";
    var accessKeyId = "<yourAccessKeyId>";
    var accessKeySecret = "<yourAccessKeySecret>";
    var bucketName = "<yourBucketName>";
    var objectName = "<yourObjectName>";
    var localFilename = "<yourLocalFilename>";
    String UrlEncodeKey(String key)
    {
    const string CharsetName = "utf-8";
    const char separator = '/';
    var segments = key.Split(separator);
    
    var encodedKey = new StringBuilder();
    encodedKey.Append(HttpUtils.EncodeUri(segments[0], CharsetName));
    for (var i = 1; i < segments.Length; i++)
        encodedKey.Append(separator).Append(HttpUtils.EncodeUri(segments[i], CharsetName));
    
        if (key.EndsWith(separator.ToString()))
        {
            // String#split ignores trailing empty strings, e.g., "a/b/" will be split as a 2-entries array,
            // so we have to append all the trailing slash to the uri.
            foreach (var ch in key)
            {
                if (ch == separator)
                    encodedKey.Append(separator);
                else
                    break;
            }
        }
    
    return encodedKey.ToString();
    }
    // 创建OssClient实例。
    var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
    // 第一次追加的位置是0,返回值为下一次追加的位置。后续追加的位置是追加前文件的长度。
    long position = 0;
    try
    {
        var metadata = client.GetObjectMetadata(bucketName, objectName);
        position = metadata.ContentLength;
    }
    catch (Exception) { }
    try
    {
        using (var fs = File.Open(localFilename, FileMode.Open))
        {
            var request = new AppendObjectRequest(bucketName, objectName)
            {
                ObjectMetadata = new ObjectMetadata(),
                Content = fs,
                Position = position
            };
    
            var meta = new ObjectMetadata();
            // 在HTTP header中设置标签信息。
             string str = UrlEncodeKey("key1") + "=" + UrlEncodeKey("key1") + "&" + UrlEncodeKey("key2") + "=" + UrlEncodeKey("key2");
            meta.AddHeader("x-oss-tagging", str);
            request.Metadata = meta;
    
            // 第一次追加。只有第一次追加上传时设置的标签生效。
            var result = client.AppendObject(request);
            // 设置文件的追加位置。
            position = result.NextAppendPosition;
            Console.WriteLine("Append object succeeded, next append position:{0}", position);
        }
        // 获取追加位置,再次追加文件。
        using (var fs = File.Open(localFilename, FileMode.Open))
        {
            var request = new AppendObjectRequest(bucketName, objectName)
            {
                ObjectMetadata = new ObjectMetadata(),
                Content = fs,
                Position = position
            };
            var result = client.AppendObject(request);
            position = result.NextAppendPosition;
            Console.WriteLine("Append object succeeded, next append position:{0}", position);
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("Append object failed, {0}", ex.Message);
    }
  • 断点续传上传时添加对象标签

    以下代码用于断点续传上传时添加对象标签:

    using Aliyun.OSS;
    using Aliyun.OSS.Common;
    using System.Text;
    var endpoint = "<yourEndpoint>";
    var accessKeyId = "<yourAccessKeyId>";
    var accessKeySecret = "<yourAccessKeySecret>";
    var bucketName = "<yourBucketName>";
    var objectName = "<yourObjectName>";
    var localFilename = "<yourLocalFilename>";
    string checkpointDir = "<yourCheckpointDir>";
    String UrlEncodeKey(String key)
    {
    const string CharsetName = "utf-8";
    const char separator = '/';
    var segments = key.Split(separator);
    
    var encodedKey = new StringBuilder();
    encodedKey.Append(HttpUtils.EncodeUri(segments[0], CharsetName));
    for (var i = 1; i < segments.Length; i++)
        encodedKey.Append(separator).Append(HttpUtils.EncodeUri(segments[i], CharsetName));
    
        if (key.EndsWith(separator.ToString()))
        {
            // String#split ignores trailing empty strings, e.g., "a/b/" will be split as a 2-entries array,
            // so we have to append all the trailing slash to the uri.
            foreach (var ch in key)
            {
                if (ch == separator)
                    encodedKey.Append(separator);
                else
                    break;
            }
        }
    
    return encodedKey.ToString();
    }
    // 创建OssClient实例。
    var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
    try
    {
        // 通过UploadFileRequest设置多个参数。
        UploadObjectRequest request = new UploadObjectRequest(bucketName, objectName, localFilename)
        {
            // 指定上传的分片大小。
            PartSize = 8 * 1024 * 1024,
            // 指定并发线程数。
            ParallelThreadCount = 3,
            // checkpointDir用于记录本地分片上传结果的文件。上传过程中的进度信息会保存在此文件中,如果某一分片上传失败,再次上传时会根据文件中记录的点继续上传。如果checkpointDir设置为null,断点续传功能不会生效,每次上传失败后都会重新上传。
            CheckpointDir = checkpointDir,
        };
    
        var meta = new ObjectMetadata();
        // 在HTTP header中设置标签信息。
        string str = UrlEncodeKey("key1") + "=" + UrlEncodeKey("key1") + "&" + UrlEncodeKey("key2") + "=" + UrlEncodeKey("key2");
        meta.AddHeader("x-oss-tagging", str);
        request.Metadata = meta;
    
        // 断点续传上传。
        client.ResumableUploadObject(request);
        Console.WriteLine("Resumable upload object:{0} succeeded", objectName);
    }
    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);
    }

对已上传Object添加或更改对象标签

以下代码用于对已上传Object添加或更改对象标签:

using Aliyun.OSS;
var endpoint = "<yourEndpoint>";
var accessKeyId = "<yourAccessKeyId>";
var accessKeySecret = "<yourAccessKeySecret>";
var bucketName = "<yourBucketName>";
var objectName = "<yourObjectName>";
// 创建OssClient实例。
var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
try
{
    // 设置标签信息。
    var setRequest = new SetObjectTaggingRequest(bucketName, objectName);

    var tag1 = new Tag
    {
        Key = "project",
        Value = "projectone"
    };

    var tag2 = new Tag
    {
        Key = "user",
        Value = "jsmith"
    };

    setRequest.AddTag(tag1);
    setRequest.AddTag(tag2);
    client.SetObjectTagging(setRequest);
    Console.WriteLine("set object tagging succeeded");
}
catch (Exception ex)
{
    Console.WriteLine("set object tagging failed. {0}", ex.Message);
}

拷贝Object时设置对象标签

拷贝Object时,可以指定如何设置目标Object的对象标签。取值如下:
  • Copy(默认值):复制源Object的对象标签到目标Object。
  • Replace:忽略源Object的对象标签,直接采用请求中指定的对象标签。

以下分别提供了简单拷贝1 GB以下的Object及分片拷贝1 GB以上的Object时设置对象标签的详细示例。

  • 以下代码用于简单拷贝1 GB以下的Object时设置对象标签:
    using Aliyun.OSS;
    using Aliyun.OSS.Common;
    using System.Text;
    var endpoint = "<yourEndpoint>";
    var accessKeyId = "<yourAccessKeyId>";
    var accessKeySecret = "<yourAccessKeySecret>";
    var sourceBucket = "<yourSourceBucketName>";
    var sourceObject = "<yourSourceObjectName>";
    var targetBucket = "<yourDestBucketName>";
    var targetObject = "<yourDestObjectName>";
    
    String UrlEncodeKey(String key)
    {
    const string CharsetName = "utf-8";
    const char separator = '/';
    var segments = key.Split(separator);
    
    var encodedKey = new StringBuilder();
    encodedKey.Append(HttpUtils.EncodeUri(segments[0], CharsetName));
    for (var i = 1; i < segments.Length; i++)
        encodedKey.Append(separator).Append(HttpUtils.EncodeUri(segments[i], CharsetName));
    
        if (key.EndsWith(separator.ToString()))
        {
            // String#split ignores trailing empty strings, e.g., "a/b/" will be split as a 2-entries array,
            // so we have to append all the trailing slash to the uri.
            foreach (var ch in key)
            {
                if (ch == separator)
                    encodedKey.Append(separator);
                else
                    break;
            }
        }
    
    return encodedKey.ToString();
    }
    // 创建OssClient实例。
    var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
    try
    {
        var metadata = new ObjectMetadata();
        metadata.AddHeader("mk1", "mv1");
        metadata.AddHeader("mk2", "mv2");
    
        // 在HTTP header中设置标签信息。
        string str = UrlEncodeKey("key1") + "=" + UrlEncodeKey("key1") + "&" + UrlEncodeKey("key2") + "=" + UrlEncodeKey("key2");
        metadata.AddHeader("x-oss-tagging", str);
    
        var req = new CopyObjectRequest(sourceBucket, sourceObject, targetBucket, targetObject)
        {
            // 如果NewObjectMetadata为null,则表示Copy模式(即拷贝源文件的元信息);非null则表示Replace模式(即覆盖源文件的元信息)。
            NewObjectMetadata = metadata 
        };
        // 拷贝文件。
        client.CopyObject(req);
        Console.WriteLine("Copy object succeeded");
    }
    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);
    }
  • 以下代码用于分片拷贝1 GB以上的Object时设置对象标签:
    using Aliyun.OSS;
    using System.Text;
    var endpoint = "<yourEndpoint>";
    var accessKeyId = "<yourAccessKeyId>";
    var accessKeySecret = "<yourAccessKeySecret>";
    var sourceBucket = "<yourSourceBucketName>";
    var sourceObject = "<yourSourceObjectName>";
    var targetBucket = "<yourDestBucketName>";
    var targetObject = "<yourDestObjectName>";
    var uploadId = "";
    var partSize = 50 * 1024 * 1024;
    String UrlEncodeKey(String key)
    {
    const string CharsetName = "utf-8";
    const char separator = '/';
    var segments = key.Split(separator);
    
    var encodedKey = new StringBuilder();
    encodedKey.Append(HttpUtils.EncodeUri(segments[0], CharsetName));
    for (var i = 1; i < segments.Length; i++)
        encodedKey.Append(separator).Append(HttpUtils.EncodeUri(segments[i], CharsetName));
    
        if (key.EndsWith(separator.ToString()))
        {
            // String#split ignores trailing empty strings, e.g., "a/b/" will be split as a 2-entries array,
            // so we have to append all the trailing slash to the uri.
            foreach (var ch in key)
            {
                if (ch == separator)
                    encodedKey.Append(separator);
                else
                    break;
            }
        }
    
    return encodedKey.ToString();
    }
    // 创建OssClient实例。
    var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
    try
    {
        // 初始化拷贝任务。您可以通过InitiateMultipartUploadRequest指定目标文件元信息。
        var request = new InitiateMultipartUploadRequest(targetBucket, targetObject);
        var meta = new ObjectMetadata();
        // 在HTTP header中设置标签信息。
        string str = UrlEncodeKey("key1") + "=" + UrlEncodeKey("key1") + "&" + UrlEncodeKey("key2") + "=" + UrlEncodeKey("key2");
        meta.AddHeader("x-oss-tagging", str);
        request.Metadata = meta;
    
        var result = client.InitiateMultipartUpload(request);
        // 打印uploadId。
        uploadId = result.UploadId;
        Console.WriteLine("Init multipart upload succeeded, Upload Id: {0}", result.UploadId);
        // 计算分片数。
        var metadata = client.GetObjectMetadata(sourceBucket, sourceObject);
        var fileSize = metadata.ContentLength;
        var partCount = (int)fileSize / partSize;
        if (fileSize % partSize != 0)
        {
            partCount++;
        }
        // 开始分片拷贝。
        var partETags = new List<PartETag>();
        for (var i = 0; i < partCount; i++)
        {
            var skipBytes = (long)partSize * i;
            var size = (partSize < fileSize - skipBytes) ? partSize : (fileSize - skipBytes);
            // 创建UploadPartCopyRequest并通过UploadPartCopyRequest指定限定条件。
            var uploadPartCopyRequest = new UploadPartCopyRequest(targetBucket, targetObject, sourceBucket, sourceObject, uploadId)
                {
                    PartSize = size,
                    PartNumber = i + 1,
                    // BeginIndex用来定位此次上传分片开始所对应的位置。
                    BeginIndex = skipBytes
                };
            // 调用uploadPartCopy方法来拷贝每一个分片。
            var uploadPartCopyResult = client.UploadPartCopy(uploadPartCopyRequest);
            Console.WriteLine("UploadPartCopy : {0}", i);
            partETags.Add(uploadPartCopyResult.PartETag);
        }
        // 完成分片拷贝。
        var completeMultipartUploadRequest =
        new CompleteMultipartUploadRequest(targetBucket, targetObject, uploadId);
        // partETags为分片上传中保存的partETag的列表,OSS收到用户提交的此列表后,会逐一验证每个数据分片的有效性。全部验证通过后,OSS会将这些分片合成一个完整的文件。
        foreach (var partETag in partETags)
        {
            completeMultipartUploadRequest.PartETags.Add(partETag);
        }
        var completeMultipartUploadResult = client.CompleteMultipartUpload(completeMultipartUploadRequest);
        Console.WriteLine("CompleteMultipartUpload succeeded");
    }
    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);
    }

为软链接文件设置标签

以下代码用于为软链接文件设置标签:

using Aliyun.OSS;
using System.Text;
var endpoint = "<yourEndpoint>";
var accessKeyId = "<yourAccessKeyId>";
var accessKeySecret = "<yourAccessKeySecret>";
var bucketName = "<yourBucketName>";
var targetObjectName = "<yourTargetObjectName>";
var symlinkObjectName = "<yourSymlinkObjectName>";
var objectContent = "More than just cloud.";
String UrlEncodeKey(String key)
{
const string CharsetName = "utf-8";
const char separator = '/';
var segments = key.Split(separator);

var encodedKey = new StringBuilder();
encodedKey.Append(HttpUtils.EncodeUri(segments[0], CharsetName));
for (var i = 1; i < segments.Length; i++)
    encodedKey.Append(separator).Append(HttpUtils.EncodeUri(segments[i], CharsetName));

    if (key.EndsWith(separator.ToString()))
    {
        // String#split ignores trailing empty strings, e.g., "a/b/" will be split as a 2-entries array,
        // so we have to append all the trailing slash to the uri.
        foreach (var ch in key)
        {
            if (ch == separator)
                encodedKey.Append(separator);
            else
                break;
        }
    }

return encodedKey.ToString();
}
// 创建OssClient实例。
var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
try
{
    // 上传目标文件。
    byte[] binaryData = Encoding.ASCII.GetBytes(objectContent);
    MemoryStream requestContent = new MemoryStream(binaryData);
    client.PutObject(bucketName, targetObjectName, requestContent);

    var meta = new ObjectMetadata();
    // 在HTTP header中设置标签信息。
    string str = UrlEncodeKey("key1") + "=" + UrlEncodeKey("key1") + "&" + UrlEncodeKey("key2") + "=" + UrlEncodeKey("key2");
    meta.AddHeader("x-oss-tagging", str);
    var request = new CreateSymlinkRequest(bucketName, symlinkObjectName, targetObjectName);
    request.ObjectMetadata = meta;
    // 创建软链接。
    client.CreateSymlink(request);
    // 获取软链接指向的目标文件名称。
    var ossSymlink = client.GetSymlink(bucketName, symlinkObjectName);
    Console.WriteLine("Target object is {0}", ossSymlink.Target);
}
catch (Exception ex)
{
    Console.WriteLine("Failed with error info: {0}", ex.Message);
}