本文介绍如何将源Bucket中的文件(Object)复制到同一地域下相同或不同目标Bucket中。

注意事项

  • 拷贝文件时,您必须拥有源文件的读权限及目标Bucket的读写权限。
  • 拷贝文件时,您需要确保源Bucket和目标Bucket均未设置合规保留策略,否则报错The object you specified is immutable.
  • 不支持跨地域拷贝。例如不能将华东1(杭州)地域存储空间中的文件拷贝到华北1(青岛)地域。

拷贝小文件

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

using Aliyun.OSS;
using Aliyun.OSS.Common;

// 填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
var endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
var accessKeyId = "yourAccessKeyId";
var accessKeySecret = "yourAccessKeySecret";
// 填写源Bucket名称,例如srcexamplebucket。
var sourceBucket = "srcexamplebucket";
// 填写源Object的完整路径,完整路径中不能包含Bucket名称,例如srcdir/scrobject.txt。
var sourceObject = "srcdir/scrobject.txt";
// 填写与源Bucket处于同一地域的目标Bucket名称,例如destbucket。
var targetBucket = "destbucket";
// 填写目标Object的完整路径,完整路径中不能包含Bucket名称,例如destdir/destobject.txt。
var targetObject = "destdir/destobject.txt";

// 创建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 
    };
    // 拷贝文件。
    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的文件,需要使用分片拷贝(UploadPartCopy)。分片拷贝分为三步:

    1. 使用InitiateMultipartUploadRequest方法来初始化一个分片上传事件。
    2. 使用UploadPartCopy方法进行分片拷贝。
    3. 使用CompleteMultipartUpload方法完成文件拷贝。

    以下代码用于分片拷贝文件:

    using Aliyun.OSS;
    // 填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
    var endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
    // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
    var accessKeyId = "yourAccessKeyId";
    var accessKeySecret = "yourAccessKeySecret";
    // 填写源Bucket名称,例如srcexamplebucket。
    var sourceBucket = "srcexamplebucket";
    // 填写源Object的完整路径,完整路径中不能包含Bucket名称,例如srcdir/scrobject.txt。
    var sourceObject = "srcdir/scrobject.txt";
    // 填写与源Bucket处于同一地域的目标Bucket名称,例如destbucket。
    var targetBucket = "destbucket";
    // 填写目标Object的完整路径,完整路径中不能包含Bucket名称,例如destdir/destobject.txt。
    var targetObject = "destdir/destobject.txt";
    var uploadId = "";
    var partSize = 50 * 1024 * 1024;
    // 创建OssClient实例。
    var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
    try
    {
        // 初始化拷贝任务。可以通过InitiateMultipartUploadRequest指定目标文件元信息。
        var request = new InitiateMultipartUploadRequest(targetBucket, targetObject);
        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;
    // 填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
    var endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
    // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
    var accessKeyId = "yourAccessKeyId";
    var accessKeySecret = "yourAccessKeySecret";
    // 填写源Bucket名称,例如srcexamplebucket。
    var sourceBucket = "srcexamplebucket";
    // 填写源Object的完整路径,完整路径中不能包含Bucket名称,例如srcdir/scrobject.txt。
    var sourceObject = "srcdir/scrobject.txt";
    // 填写与源Bucket处于同一地域的目标Bucket名称,例如destbucket。
    var targetBucket = "destbucket";
    // 填写目标Object的完整路径,完整路径中不能包含Bucket名称,例如destdir/destobject.txt。
    var targetObject = "destdir/destobject.txt";
    // 记录拷贝结果的文件。拷贝过程中的进度信息会保存在该文件中,如果拷贝失败,再次拷贝时会根据文件中记录的点继续拷贝。拷贝完成后,该文件会被删除。
    var checkpointDir = @"yourCheckpointDir";
    // 创建OssClient实例。
    var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
    try
    {
        var request = new CopyObjectRequest(sourceBucket, sourceObject, targetBucket, targetObject);
        // checkpointDir目录中会保存断点续传的中间状态,用于失败后,下次继续拷贝。如果checkpointDir为null,断点续传功能不会生效,每次都会重新拷贝。
        client.ResumableCopyObject(request, checkpointDir);
        Console.WriteLine("Resumable copy new object:{0} succeeded", request.DestinationKey);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Resumable copy new object failed, {0}", ex.Message);
    }

相关文档

  • 拷贝小文件
    • 关于拷贝小文件的完整示例代码,请参见GitHub示例
    • 关于拷贝小文件的API接口说明,请参见CopyObject
  • 拷贝大文件
    • 关于拷贝大文件的完整示例代码,请参见GitHub示例
    • 关于拷贝大文件的API接口说明,请参见UploadPartCopy
  • 断点续传拷贝

    关于断点续传拷贝的完整示例代码,请参见GitHub示例