拷贝文件

本文介绍如何在受版本控制的存储空间(Bucket)中拷贝文件(Object)。您可以通过CopyObject的方法拷贝小于1 GB的文件,通过分片拷贝(UploadPartCopy)的方法拷贝大于1 GB的文件。

注意事项

  • 本文以华东1(杭州)外网Endpoint为例。如果您希望通过与OSS同地域的其他阿里云产品访问OSS,请使用内网Endpoint。关于OSS支持的Region与Endpoint的对应关系,请参见访问域名和数据中心

  • 本文以OSS域名新建OSSClient为例。如果您希望通过自定义域名、STS等方式新建OSSClient,请参见初始化

  • 要拷贝文件,您必须有oss:GetObjectoss:PutObject权限。具体操作,请参见为RAM用户授权自定义的权限策略

拷贝小文件

对于小于1 GB的文件,您可以通过CopyObject方法将文件从一个存储空间(源存储空间)复制到同一地域的另一个存储空间(目标存储空间)。

  • x-oss-copy-source默认拷贝Object的当前版本。如果当前版本是删除标记,则返回404表示该Object不存在。您可以在x-oss-copy-source中加入versionId来拷贝指定的Object版本,删除标记不能被拷贝。

  • 您可以将Object的早期版本拷贝到同一个Bucket中,拷贝Object的历史版本将会成为一个新的当前版本,达到恢复Object早期版本的目的。

  • 如果目标Bucket已开启版本控制,OSS将会为新拷贝出来的Object自动生成唯一的版本ID,此版本ID将会在响应header的x-oss-version-id中返回。如果目标Bucket未曾开启或者暂停了版本控制,OSS将会为新拷贝的Object自动生成version ID为“null”的版本,且会覆盖原先versionId为“null”的版本。

  • 目标Bucket在开启或暂停版本控制状态下,不支持对Appendable类型Object执行拷贝操作。

以下代码用于拷贝小文件:

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);
}

拷贝大文件

对于大于1 GB的文件,需要使用分片拷贝(UploadPartCopy)。

UploadPartCopy默认从一个已存在的Object的当前版本中拷贝数据来上传一个Part。允许通过在请求header : x-oss-copy-source中附带versionId的子条件,实现从Object的指定版本进行拷贝,例如x-oss-copy-source : /SourceBucketName/SourceObjectName?versionId=CAEQMxiBgICAof2D0BYiIDJhMGE3N2M1YTI1NDQzOGY5NTkyNTI3MGYyMzJm****。

说明

SourceObjectName要进行URL编码。响应中将会返回被拷贝的Object版本ID,即x-oss-copy-source-version-id。

如果未指定versionId且拷贝Object的当前版本为删除标记,OSS将返回404 Not Found。通过指定versionId来拷贝删除标记时,OSS将返回400 Bad Request。

以下代码用于分片拷贝:

using System;
using System.Collections.Generic;
using Aliyun.OSS;
using Aliyun.OSS.Common;

namespace Samples
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
            var endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
            // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量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 sourceObjectVersionid = "yourSourceObjectVersionid";
            var partSize = 50 * 1024 * 1024;
            // 创建OSSClient实例。
            var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
            try
            {
                // 初始化拷贝任务。您可以通过InitiateMultipartUploadRequest指定目标文件元数据。
                var initRequest = new InitiateMultipartUploadRequest(targetBucket, targetObject);
                var result = client.InitiateMultipartUpload(initRequest);
                // 打印uploadId。
                var uploadId = result.UploadId;
                Console.WriteLine("Init multipart upload succeeded, Upload Id: {0}", result.UploadId);
                // 计算分片数。
                var request = new GetObjectMetadataRequest(sourceBucket, sourceObject)
                {
                    // 指定Object的版本ID。
                    VersionId = sourceObjectVersionid
                };
                var metadata = client.GetObjectMetadata(request);
                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,
                        // 指定Object的版本ID。
                        VersionId = sourceObjectVersionid
                    };
                    // 调用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, vesionid:{0}", completeMultipartUploadResult.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);
            }
        }
    }
}

相关文档

  • 关于拷贝小文件的API接口说明,请参见CopyObject

  • 关于拷贝大文件的API接口说明,请参见UploadPartCopy