如果需要上传较大的对象,建议分成多个数据块(part)来分别上传,最后调用合并分片将上传的数据块合并为一个对象。
使用 TOS .NET SDK 进行分片上传包含以下三个步骤。
createMultipartUpload
接口返回 TOS 创建的全局唯一的uploadId
。uploadPart
接口上传分片数据。说明
uploadId
标识),分片编号(partNumber
)标识了该分片在整个对象中的相对位置。若通过同一分片编号多次上传数据,TOS 会覆盖已有的数据,并以最后一次上传的数据为准。uploadPart
接口返回分片数据的 MD5 值,可通过 ETag
字段获取。合并分片时,您需指定当前分片上传任务中已上传的所有分片信息(分片编号、ETag值)。completeMultipartUpload
接口将所有分片合并成一个完整的对象。以下代码用于将本地文件通过分片的方式上传完整过程,并在上传时指定 ACL 为 Private、存储类型为低频存储以及添加自定义元数据。
using System;
using System.Collections.Generic;
using System.IO;
using TOS;
using TOS.Error;
using TOS.Model;
namespace ConsoleApp
{
internal class Program
{
private static void Main(string[] args)
{
var ak = Environment.GetEnvironmentVariable("TOS_ACCESS_KEY");
var sk = Environment.GetEnvironmentVariable("TOS_SECRET_KEY");
// endpoint 若没有指定HTTP协议(HTTP/HTTPS),默认使用 HTTPS
// Bucket 的 Endpoint,以华北2(北京)为例:https://tos-cn-beijing.volces.com
var endpoint = "https://tos-cn-beijing.volces.com";
var region = "cn-beijing";
// 填写 BucketName
var bucketName = "*** Provide your bucket name ***";
// 将文件上传到 example_dir 目录下的 example.txt 文件
var objectKey = "example_dir/example.txt";
// 需要上传的本地文件
var localFileName = "/usr/local/test.txt";
// 创建TOSClient实例
var client = TosClientBuilder.Builder().SetAk(ak).SetSk(sk).SetEndpoint(endpoint).SetRegion(region).Build();
// 初始化分片,指定对象权限为私有,存储类型为低频并设置元数据信息
var uploadID = "";
try
{
var createMultipartUploadInput = new CreateMultipartUploadInput
{
Bucket = bucketName,
Key = objectKey,
ACL = ACLType.ACLPrivate,
StorageClass = StorageClassType.StorageClassIa,
Meta = new Dictionary<string, string> { { "key", "value" } }
};
var createMultipartUploadOutput = client.CreateMultipartUpload(createMultipartUploadInput);
uploadID = createMultipartUploadOutput.UploadID;
Console.WriteLine("CreateMultipartUpload succeeded, request id {0}",
createMultipartUploadOutput.RequestID);
Console.WriteLine("CreateMultipartUpload succeeded, upload id {0}", uploadID);
}
catch (TosServerException ex)
{
Console.WriteLine("CreateMultipartUpload failed, request id {0}", ex.RequestID);
Console.WriteLine("CreateMultipartUpload failed, status code {0}", ex.StatusCode);
Console.WriteLine("CreateMultipartUpload failed, response error code {0}", ex.Code);
Console.WriteLine("CreateMultipartUpload failed, response error message {0}", ex.Message);
}
catch (TosClientException ex)
{
Console.WriteLine("CreateMultipartUpload failed, error message {0}", ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("CreateMultipartUpload failed, {0}", ex.Message);
}
// part size 大小设置为 20M
long partSize = 20 * 1024 * 1024;
// 计算分片信息
var fi = new FileInfo(localFileName);
var fileSize = fi.Length;
var partCount = fileSize / partSize;
if (fileSize % partSize != 0) partCount++;
var parts = new UploadedPart[partCount];
// 开始分片上传
try
{
using (var fileStream = File.Open(localFileName, FileMode.Open, FileAccess.Read))
{
for (var i = 0; i < partCount; i++)
{
var offset = partSize * i;
// 定位到本次上传的起始位置。
fileStream.Seek(offset, 0);
// 计算本次上传的分片大小,最后一片为剩余的数据大小。
var contentSize = partSize < fileSize - offset ? partSize : fileSize - offset;
var UploadPartInput = new UploadPartInput
{
Bucket = bucketName,
Key = objectKey,
UploadID = uploadID,
// partNumber 编号从 1 开始
PartNumber = i + 1,
Content = fileStream,
ContentLength = contentSize
};
var uploadPartOutput = client.UploadPart(UploadPartInput);
parts[i] = new UploadedPart { PartNumber = i + 1, ETag = uploadPartOutput.ETag };
Console.WriteLine("UploadPart succeeded, request id {0}", uploadPartOutput.RequestID);
}
}
}
catch (TosServerException ex)
{
Console.WriteLine("UploadPart failed, request id {0}", ex.RequestID);
Console.WriteLine("UploadPart failed, status code {0}", ex.StatusCode);
Console.WriteLine("UploadPart failed, response error code {0}", ex.Code);
Console.WriteLine("UploadPart failed, response error message {0}", ex.Message);
}
catch (TosClientException ex)
{
Console.WriteLine("UploadPart failed, error message {0}", ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("UploadPart failed, {0}", ex.Message);
}
// 合并分片
try
{
var completeMultipartUploadInput = new CompleteMultipartUploadInput
{
Bucket = bucketName,
Key = objectKey,
UploadID = uploadID,
Parts = parts
};
var completeMultipartUploadOutput = client.CompleteMultipartUpload(completeMultipartUploadInput);
Console.WriteLine("CompleteMultipartUpload succeeded, request id {0}",
completeMultipartUploadOutput.RequestID);
}
catch (TosServerException ex)
{
Console.WriteLine("CompleteMultipartUpload failed, request id {0}", ex.RequestID);
Console.WriteLine("CompleteMultipartUpload failed, status code {0}", ex.StatusCode);
Console.WriteLine("CompleteMultipartUpload failed, response error code {0}", ex.Code);
Console.WriteLine("CompleteMultipartUpload failed, response error message {0}", ex.Message);
}
catch (TosClientException ex)
{
Console.WriteLine("CompleteMultipartUpload failed, error message {0}", ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("CompleteMultipartUpload failed, {0}", ex.Message);
}
}
}
}
以下代码用于列举存储桶中指定对象已上传的分片信息。
using System;
using TOS;
using TOS.Error;
using TOS.Model;
namespace ConsoleApp
{
internal class Program
{
private static void Main(string[] args)
{
var ak = Environment.GetEnvironmentVariable("TOS_ACCESS_KEY");
var sk = Environment.GetEnvironmentVariable("TOS_SECRET_KEY");
// endpoint 若没有指定HTTP协议(HTTP/HTTPS),默认使用 HTTPS
// Bucket 的 Endpoint,以华北2(北京)为例:https://tos-cn-beijing.volces.com
var endpoint = "https://tos-cn-beijing.volces.com";
var region = "cn-beijing";
// 填写 BucketName
var bucketName = "*** Provide your bucket name ***";
// 填写对象名
var objectKey = "*** Provide your object key ***";
// 填写分片对象对应的upload id
var uploadID = "*** Provide upload ID ***";
// 创建TOSClient实例
var client = TosClientBuilder.Builder().SetAk(ak).SetSk(sk).SetEndpoint(endpoint).SetRegion(region).Build();
try
{
// 列举 uploadID 已上传分片信息
var truncated = true;
var marker = 0;
while (truncated)
{
var createMultipartUploadInput = new ListPartsInput
{
Bucket = bucketName,
Key = objectKey,
UploadID = uploadID,
PartNumberMarker = marker
};
var listPartsOutput = client.ListParts(createMultipartUploadInput);
truncated = listPartsOutput.IsTruncated;
marker = listPartsOutput.NextPartNumberMarker;
Console.WriteLine("ListParts succeeded, request id {0}", listPartsOutput.RequestID);
Console.WriteLine("ListParts succeeded, upload id {0}", uploadID);
foreach (var part in listPartsOutput.Parts)
{
Console.WriteLine("ListParts succeeded, part number {0}", part.PartNumber);
Console.WriteLine("ListParts succeeded, part Etag {0}", part.ETag);
Console.WriteLine("ListParts succeeded, part size {0}", part.Size);
}
}
}
catch (TosServerException ex)
{
Console.WriteLine("ListParts failed, request id {0}", ex.RequestID);
Console.WriteLine("ListParts failed, status code {0}", ex.StatusCode);
Console.WriteLine("ListParts failed, response error code {0}", ex.Code);
Console.WriteLine("ListParts failed, response error message {0}", ex.Message);
}
catch (TosClientException ex)
{
Console.WriteLine("ListParts failed, error message {0}", ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("ListParts failed, {0}", ex.Message);
}
}
}
}
您可以通过 AbortMultipartUpload 接口取消分片上传任务。当一个分片任务被取消后, TOS 会将已上传的分片数据删除,同时您无法再对此分片任务进行任何操作。
以下代码用于取消分片上传任务。
using System;
using TOS;
using TOS.Error;
using TOS.Model;
namespace ConsoleApp
{
internal class Program
{
private static void Main(string[] args)
{
var ak = Environment.GetEnvironmentVariable("TOS_ACCESS_KEY");
var sk = Environment.GetEnvironmentVariable("TOS_SECRET_KEY");
// endpoint 若没有指定HTTP协议(HTTP/HTTPS),默认使用 HTTPS
// Bucket 的 Endpoint,以华北2(北京)为例:https://tos-cn-beijing.volces.com
var endpoint = "https://tos-cn-beijing.volces.com";
var region = "cn-beijing";
// 填写 BucketName
var bucketName = "*** Provide your bucket name ***";
// 填写对象名
var objectKey = "*** Provide your object key ***";
// 填写分片对象对应的upload id
var uploadID = "*** Provide upload ID ***";
// 创建TOSClient实例
var client = TosClientBuilder.Builder().SetAk(ak).SetSk(sk).SetEndpoint(endpoint).SetRegion(region).Build();
try
{
// 取消分片上传
var abortMultipartUploadInput = new AbortMultipartUploadInput()
{
Bucket = bucketName,
Key = objectKey,
UploadID = uploadID,
};
var abortMultipartUploadOutput = client.AbortMultipartUpload(abortMultipartUploadInput);
Console.WriteLine("AbortMultipartUpload succeeded, request id {0}", abortMultipartUploadOutput.RequestID);
}
catch (TosServerException ex)
{
Console.WriteLine("AbortMultipartUpload failed, request id {0}", ex.RequestID);
Console.WriteLine("AbortMultipartUpload failed, status code {0}", ex.StatusCode);
Console.WriteLine("AbortMultipartUpload failed, response error code {0}", ex.Code);
Console.WriteLine("AbortMultipartUpload failed, response error message {0}", ex.Message);
}
catch (TosClientException ex)
{
Console.WriteLine("AbortMultipartUpload failed, error message {0}", ex.Message);
}
catch (Exception ex)
{
Console.WriteLine("AbortMultipartUpload failed, {0}", ex.Message);
}
}
}
}