Object管理
上传Object
最简单的上传
-
基本流程
- 创建一个BOSClient类的实例。
- 调用BOSClient.PutObject()方法。调用该方法时您需要提供Bucket名称、ObjectKey和Object的内容。可以通过如下四种方式上传Object:文件、数据流、二进制串和字符串的形式。
-
示例代码
public void PutObject(BosClient client, String bucketName, String objectKey, byte[] byte1, String string1) { // 获取指定文件 FileInfo file = new FileInfo(<FilePath>); //指定文件路径 // 以文件形式上传Object PutObjectResponse putObjectFromFileResponse = client.PutObject(bucketName, objectKey, file); // 获取数据流 Stream inputStream = file.OpenRead(); // 以数据流形式上传Object PutObjectResponse putObjectResponseFromInputStream = client.PutObject(bucketName, objectKey, inputStream); // 以二进制串上传Object PutObjectResponse putObjectResponseFromByte = client.PutObject(bucketName, objectKey,Encoding.Default.GetBytes("sampledata")); // 以字符串上传Object PutObjectResponse putObjectResponseFromString = client.PutObject(bucketName, objectKey, "sampledata"); // 打印ETag Console.WriteLine(putObjectFromFileResponse.ETAG); }
说明:Object以文件的形式上传到BOS中,putObject函数支持不超过5GB的Object上传。在putObject请求处理成功后,BOS会在Header中返回Object的ETag作为文件标识。
-
完整示例
请参考完整示例。
设定Object的Http Header
BOS支持您在上传object时设定Http Header。
-
基本流程
- 创建一个BOSClient类的实例。
- 调用BOSClient.PutObject()时候,您还可以传入一个ObjectMetadata对象,该对象可以设置自定义的Http Header。
-
示例代码
// 初始化上传输入流 ObjectMetadata meta = new ObjectMetadata(); // 设置ContentLength大小 meta.ContentLength = <Length>; // 设置ContentType meta.ContentType = "application/json"; client.PutObject(bucketName, objectKey, <SampleData>, meta);
-
完整示例
请参考完整示例。
用户自定义元数据
-
基本流程
- 创建一个BOSClient类的实例。
- 调用BOSClient.PutObject()时候,您还可以传入一个ObjectMetadata对象,该对象支持用户自定义元数据来对Object进行描述。
-
示例代码
// 设置自定义元数据name的值为my-data meta.UserMetadata["name"] = "my-data"; // 上传Object client.PutObject(bucketName, objectKey, <SampleData>, meta);
说明:在上面代码中,用户自定义了一个名字为”name”,值为”my-data”的元数据。当用户下载此Object的时候,此元数据也可以一并得到。一个Object可以有多个类似的参数,但所有的User Meta总大小不能超过2KB。
-
完整示例
请参考完整示例。
完整示例
下面示例代码演示了简单上传Object、设定Object的Http Header和用户自定义元数据的完整过程:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using BaiduBce;
using BaiduBce.Auth;
using BaiduBce.Services.Bos;
using BaiduBce.Services.Bos.Model;
namespace DotnetSample
{
internal class PutObjectSample
{
private static void Main(string[] args)
{
BosClient client = GenerateBosClient();
const string bucketName = <BucketName>; //您的Bucket名称
const string objectNameFile = <ObjectNameFile>; //文件形式上传的Object名称
const string objectNameStream = <ObjectNameStream>; //数据流形式上传的Object名称
const string objectNameString = <ObjectNameString>; //字符串形式上传的Object名称
const string objectNameByte = <ObjectNameByte>; //二进制形式上传的Object名称
// 新建一个Bucket
client.CreateBucket(bucketName); //指定Bucket名称
// 设置待上传的文件名
const string fileName = "d:\\sample.txt";
// 以文件形式上传Object
PutObjectResponse putObjectFromFileResponse = client.PutObject(bucketName, objectNameFile,
new FileInfo(fileName));
// 以数据流形式上传Object
PutObjectResponse putObjectResponseFromInputStream = client.PutObject(bucketName, objectNameStream,
new FileInfo(fileName).OpenRead());
// 以二进制串上传Object
PutObjectResponse putObjectResponseFromByte = client.PutObject(bucketName, objectNameByte,
Encoding.Default.GetBytes("sampledata"));
// 以字符串上传Object
PutObjectResponse putObjectResponseFromString = client.PutObject(bucketName, objectNameString,
"sampledata");
// 打印四种方式的ETag。示例中,文件方式和stream方式的ETag相等,string方式和byte方式的ETag相等
Console.WriteLine(putObjectFromFileResponse.ETAG);
Console.WriteLine(putObjectResponseFromInputStream.ETAG);
Console.WriteLine(putObjectResponseFromByte.ETAG);
Console.WriteLine(putObjectResponseFromString.ETAG);
// 上传Object并设置自定义参数
ObjectMetadata meta = new ObjectMetadata();
// 设置ContentLength大小
meta.ContentLength = 10;
// 设置ContentType
meta.ContentType = "application/json";
// 设置自定义元数据name的值为my-data
meta.UserMetadata["name"] = "my-data";
// 上传Object并打印ETag
putObjectResponseFromString = client.PutObject(bucketName, objectNameString, "sampledata", meta);
Console.WriteLine(putObjectResponseFromString.ETAG);
}
private static BosClient GenerateBosClient()
{
const string accessKeyId = <AccessKeyID>; // 您的Access Key ID
const string secretAccessKey = <SecretAccessKey>; // 您的Secret Access Key
const string endpoint = "https://bj.bcebos.com"; // 指定BOS服务域名
// 初始化一个BosClient
BceClientConfiguration config = new BceClientConfiguration();
config.Credentials = new DefaultBceCredentials(accessKeyId, secretAccessKey);
config.Endpoint = endpoint;
return new BosClient(config);
}
}
}
查看Bucket中的Object
简单查询
查看Bucket中Object列表。
-
基本流程
- 创建一个BOSClient类的实例。
- 调用BOSClient.ListObjects()方法。调用该方法时你需要提供Bucket名称。
-
示例代码
public void ListObjects(BosClient client, string bucketName) { // 获取指定Bucket下的所有Object信息 ListObjectsResponse listObjectsResponse = client.ListObjects(bucketName); // 遍历所有Object foreach (BosObjectSummary objectSummary in listObjectsResponse.Contents) { Console.WriteLine("ObjectKey: " + objectSummary.Key); } }
说明: listObjects( )方法返回ListObjectsResponse对象,ListObjectsResponse对象包含了此次listObject请求的返回结果。用户可以通过ListObjectsResponse中的getContents方法获取所有Object的描述信息。
- 默认情况下,如果Bucket中的Object数量大于1000,则只会返回1000个Object,并且返回结果中IsTruncated值为True,并返回NextMarker做为下次读取的起点。
- 若想获取更多的Object,可以使用Marker参数分次读取,请参考扩展查询。
-
完整示例
请参考完整示例。
扩展查询
用户可以通过设置ListObjectsRequest参数来完成更多扩展查询操作设置。ListObjectsRequest中可以设置的扩展参数如下:
参数名称 | 说明 | 默认值 |
---|---|---|
MaxKeys | 设定此次返回Object的最大个数,不可超过1000。 | 1000 |
Prefix | 设定objectKey的前缀,前缀是指objectKey包含并以Prefix的值作为开始。 通常与Delimiter配合在查询模拟文件夹中使用。 |
- |
Delimiter | 是一个分隔符,用来对objectKey进行分层。 通常与Prefix配合在查询模拟文件夹中使用。 从Prefix开始到第一次出现Delimiter字符之间的objectKey称为:CommonPrefixes。 |
- |
Marker | 是一个字符串,用来设定返回结果的起始位置。 设定Marker值之后,返回的Object会从Marker值之后按字母排序开始返回。 |
- |
-
基本流程
- 创建一个BOSClient类的实例。
- 您也可以构造一个ListObjectsRequest来调用ListObjects(),ListObjectsRequest等方法,实现更多的扩展查询操作。
-
示例代码
// 构造ListObjectsRequest请求 ListObjectsRequest listObjectsRequest = new ListObjectsRequest() {BucketName = bucketName}; // 设置参数 listObjectsRequest.Delimiter=<Delimiter>; listObjectsRequest.Marker=<Marker>; ListObjectsResponse listObjectsResponse = client.ListObjects(listObjectsRequest);
说明:
上面代码中调用了
listObjects
中的一个重载方法,通过传入ListObjectsRequest
来完成请求。 -
完整示例
请参考完整示例。
查询模拟文件夹
由于BOS本身是一个(<Key>,<Value>
)的存储系统,所以原则上并不会存在“文件夹”的概念,但您可以通过 Delimiter
和 Prefix
参数的配合进行文件夹功能模拟。
假设Bucket中有5个文件:bos.jpg,fun/,fun/test.jpg,fun/movie/001.avi,fun/movie/007.avi,可以把 “/” 符号作为分隔符模拟文件夹。
递归列出模拟文件夹下所有文件
可以通过设置 Prefix
参数来获取某个目录下所有的文件:
// 构造ListObjectsRequest请求
ListObjectsRequest listObjectsRequest = new ListObjectsRequest() {BucketName = bucketName};
// 递归列出fun目录下的所有文件
listObjectsRequest.Prefix = "fun/";
// List Objects
ListObjectsResponse listObjectsResponse = client.ListObjects(listObjectsRequest);
// 遍历所有Object
Console.WriteLine("Objects:");
foreach (BosObjectSummary objectSummary in listObjectsResponse.Contents)
{
Console.WriteLine("ObjectKey: " + objectSummary.Key);
}
输出:
Objects:
fun/
fun/movie/001.avi
fun/movie/007.avi
fun/test.jpg
查看模拟文件夹下的文件和子文件夹
在 Prefix
和 Delimiter
结合的情况下,可以列出模拟文件夹下的文件和子文件夹:
// 构造ListObjectsRequest请求
ListObjectsRequest listObjectsRequest = new ListObjectsRequest() {BucketName = bucketName};
// "/" 为文件夹的分隔符
listObjectsRequest.Delimiter = "/";
// 列出fun目录下的所有文件和文件夹
listObjectsRequest.Prefix = "fun/";
// List Objects
ListObjectsResponse listObjectsResponse = client.ListObjects(listObjectsRequest);
// 遍历所有Object,相当于获取fun目录下的所有文件
Console.WriteLine("Objects:");
foreach (BosObjectSummary objectSummary in listObjectsResponse.Contents)
{
Console.WriteLine("ObjectKey: " + objectSummary.Key);
}
// 遍历所有CommonPrefix,相当于获取fun目录下的所有文件夹
Console.WriteLine("\nCommonPrefixs:");
foreach (ObjectPrefix objectPrefix in listObjectsResponse.CommonPrefixes)
{
Console.WriteLine(objectPrefix.Prefix);
}
输出:
Objects:
fun/
fun/test.jpg
CommonPrefixs:
fun/movie/
说明:
返回的结果中,
Objects
的列表中给出的是fun文件夹下的文件。而CommonPrefixs
的列表中给出的是fun文件夹下的所有子文件夹。可以看出fun/movie/001.avi
,fun/movie/007.avi
两个文件并没有被列出来,因为它们属于fun
文件夹下的movie
子文件夹下的文件。
-
完整示例
请参考完整示例。
完整示例
下面示例代码演示了Object的简单查询、使用nextmarker分次查询、扩展查询、查询模拟文件夹的完整过程:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BaiduBce;
using BaiduBce.Auth;
using BaiduBce.Services.Bos;
using BaiduBce.Services.Bos.Model;
namespace DotnetSample
{
internal class ListObjectsSample
{
private static void Main(string[] args)
{
BosClient client = GenerateBosClient();
const string bucketName = <BucketName>; //您的Bucket名称
// 新建一个Bucket
client.CreateBucket(bucketName);
// 创建bos.jpg,fun/,fun/test.jpg,fun/movie/001.avi,fun/movie/007.avi五个文件
client.PutObject(bucketName, "bos.jpg", "sampledata");
client.PutObject(bucketName, "fun/", "sampledata");
client.PutObject(bucketName, "fun/test.jpg", "sampledata");
client.PutObject(bucketName, "fun/movie/001.avi", "sampledata");
client.PutObject(bucketName, "fun/movie/007.avi", "sampledata");
// 构造ListObjectsRequest请求
ListObjectsRequest listObjectsRequest = new ListObjectsRequest() { BucketName = bucketName };
// 1. 简单查询,列出Bucket下所有文件
ListObjectsResponse listObjectsResponse = client.ListObjects(listObjectsRequest);
// 输出:
// Objects:
// bos.jpg
// fun/
// fun/movie/001.avi
// fun/movie/007.avi
// fun/test.jpg
Console.WriteLine("Objects:");
foreach (BosObjectSummary objectSummary in listObjectsResponse.Contents)
{
Console.WriteLine("ObjectKey: " + objectSummary.Key);
}
// 2. 使用NextMarker分次列出所有文件
listObjectsRequest.MaxKeys = 2;
listObjectsResponse = client.ListObjects(listObjectsRequest);
// 输出:
// Objects:
// bos.jpg
// fun/
// fun/movie/001.avi
// fun/movie/007.avi
// fun/test.jpg
Console.WriteLine("Objects:");
while (listObjectsResponse.IsTruncated)
{
foreach (BosObjectSummary objectSummary in listObjectsResponse.Contents)
{
Console.WriteLine("ObjectKey: " + objectSummary.Key);
}
listObjectsResponse = client.ListNextBatchOfObjects(listObjectsResponse);
}
foreach (BosObjectSummary objectSummary in listObjectsResponse.Contents)
{
Console.WriteLine("ObjectKey: " + objectSummary.Key);
}
// 3. 递归列出“fun/”下所有文件和子文件夹
listObjectsRequest.Prefix = "fun/";
listObjectsResponse = client.ListObjects(listObjectsRequest);
// 输出:
// Objects:
// fun/
// fun/movie/001.avi
// fun/movie/007.avi
// fun/test.jpg
Console.WriteLine("Objects:");
foreach (BosObjectSummary objectSummary in listObjectsResponse.Contents)
{
Console.WriteLine("ObjectKey: " + objectSummary.Key);
}
// 4. 列出“fun”下的文件和子文件夹
listObjectsRequest.Delimiter = "/";
listObjectsResponse = client.ListObjects(listObjectsRequest);
// 输出:
// Objects:
// fun/
// fun/test.jpg
Console.WriteLine("Objects:");
foreach (BosObjectSummary objectSummary in listObjectsResponse.Contents)
{
Console.WriteLine("ObjectKey: " + objectSummary.Key);
}
// 遍历所有CommonPrefix,相当于获取fun目录下的所有子文件夹
// 输出:
// CommonPrefixs:
// fun/movie
Console.WriteLine("\nCommonPrefixs:");
foreach (ObjectPrefix objectPrefix in listObjectsResponse.CommonPrefixes)
{
Console.WriteLine(objectPrefix.Prefix);
}
}
private static BosClient GenerateBosClient()
{
const string accessKeyId = <AccessKeyID>; // 您的Access Key ID
const string secretAccessKey = <SecretAccessKey>; // 您的Secret Access Key
const string endpoint = "https://bj.bcebos.com"; // 指定BOS服务域名
// 初始化一个BosClient
BceClientConfiguration config = new BceClientConfiguration();
config.Credentials = new DefaultBceCredentials(accessKeyId, secretAccessKey);
config.Endpoint = endpoint;
return new BosClient(config);
}
}
}
获取Object
简单的获取Object
-
基本流程
- 创建BOSClient类的实例。
- 执行BOSClient.GetObject()方法,会返回指定的BosObject。
- 将BosObject读到流中,然后对流进行操作。
-
示例代码
public void GetObject(BosClient client, String bucketName, String objectKey) { // 获取Object,返回结果为BosObject对象 BosObject bosObject = client.GetObject(bucketName, objectKey); // 获取ObjectMeta ObjectMetadata meta = bosObject.ObjectMetadata; // 获取Object的输入流 Stream objectContent = bosObject.ObjectContent; // 处理Object ... // 关闭流 objectContent.Close(); }
注意:
- BosObject中包含了Object的各种信息,包含Object所在的Bucket、Object的名称、MetaData以及一个输入流,
- 用户可以通过操作输入流将Object的内容读取到文件或者内存中。
- ObjectMetadata中包含了Object上传时定义的ETag,Http Header以及自定义的元数据。
- 通过BosObject的getObjectContent()方法,还可以获取返回Object的输入流,用户可以读取这个输入流来对Object的内容进行操作。
-
完整示例
请参考完整示例。
通过GetObjectRequest获取Object
为了实现更多的功能,可以通过使用GetObjectRequest来获取Object。
-
基本流程
- 创建GetObjectRequest类的实例。
- 对GetObjectRequest执行setRange( ),获取Object中所需的字节数据。
- 执行GetObject( )操作。
-
示例代码
// 新建GetObjectRequest GetObjectRequest getObjectRequest = new GetObjectRequest() {BucketName = bucketName, Key = objectKey}; // 获取0~100字节范围内的数据 getObjectRequest.SetRange(0, 100); // 获取Object,返回结果为BosObject对象 BosObject bosObject = client.GetObject(getObjectRequest);
说明:通过getObjectRequest的setRange( )方法可以设置返回Object的范围。用户可以用此功能实现文件的分段下载和断点续传。
-
完整示例
请参考完整示例。
直接下载Object到指定路径
用户可以通过如下代码直接将Object下载到指定路径。
-
基本流程
- 创建GetObjectRequest类的实例。
- 执行client.getObject( )操作。
- Object可以直接下载到指定路径。
-
示例代码
// 新建GetObjectRequest GetObjectRequest getObjectRequest = new GetObjectRequest() {BucketName = bucketName, Key = objectKey}; // 下载Object到文件 ObjectMetadata objectMetadata = client.GetObject(getObjectRequest, new FileInfo("d:\\sample.txt"));
说明:当使用上面方法将Object直接下载到指定路径时,方法会返回ObjectMetadata对象。
-
完整示例
请参考完整示例。
只获取ObjectMetadata
通过 getObjectMetadata() 方法可以只获取ObjectMetadata而不获取Object的实体。
-
示例代码
ObjectMetadata objectMetadata = client.GetObjectMetadata(bucketName, objectKey);
-
完整示例
请参考完整示例。
获取Object的URL
您可以通过如下代码获取指定Object的URL,该功能通常用于您将Object的URL临时分享给其他用户的场景。
-
基本流程
- 创建一个BOSClient类的实例。
- 调用BosClient.GeneratePresignedUrl()方法,在调用该方法时您需要提供Bucket名称,object名称,过期时间等参数。
- 返回一个Object的URL。
-
示例代码
public string GeneratePresignedUrl(BosClient client, string bucketName, string objectKey, int expirationInSeconds) { //指定用户需要获取的Object所在的Bucket名称、该Object名称、时间戳、URL的有效时长 Uri url = client.GeneratePresignedUrl(bucketName, objectKey, expirationInSeconds); return url.AbsoluteUri; }
说明:
ExpirationInSeconds
为指定的URL有效时长,时间从当前时间算起,为可选参数,不配置时系统默认值为1800秒。如果要设置为永久不失效的时间,可以将ExpirationInSeconds
参数设置为 -1,不可设置为其他负数。 -
完整示例
请参考完整示例。
完整示例
下面示例代码演示了简单获取Object、通过GetObjectRequest获取Object、直接下载Object到指定路径、只获取ObjectMetadata以及获取Object的URL的完整过程:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using BaiduBce;
using BaiduBce.Auth;
using BaiduBce.Services.Bos;
using BaiduBce.Services.Bos.Model;
namespace DotnetSample
{
internal class GetObjectsSample
{
private static void Main(string[] args)
{
BosClient client = GenerateBosClient();
const string bucketName = <BucketName>; //您的Bucket名称
// 初始化,创建Bucket和Object
client.CreateBucket(bucketName);
string objectName = <ObjectKey>;
client.PutObject(bucketName, objectName, <SampleData>);
// 获取BosObject对象并通过BosObject的输入流获取内容
BosObject bosObject = client.GetObject(bucketName, objectName);
Stream objectContent = bosObject.ObjectContent;
string content = new StreamReader(objectContent).ReadToEnd();
Console.WriteLine(content); // 您传入的<SampleData>
// 通过GetObjectRequest只获取部分数据
GetObjectRequest getObjectRequest = new GetObjectRequest() {BucketName = bucketName, Key = objectName};
getObjectRequest.SetRange(0, 5);
bosObject = client.GetObject(getObjectRequest);
objectContent = bosObject.ObjectContent;
content = new StreamReader(objectContent).ReadToEnd();
Console.WriteLine(content); // 您传入的<SampleData>
// 直接通过GetObjectContent获取byte[]内容
byte[] bytes = client.GetObjectContent(bucketName, objectName);
content = Encoding.Default.GetString(bytes);
Console.WriteLine(content); // 您传入的<SampleData>
// 将Object内容下载到文件
FileInfo fileInfo = new FileInfo("my file path and name");
client.GetObject(bucketName, objectName,fileInfo );
content = File.ReadAllText(fileInfo.FullName);
Console.WriteLine(content); // 您传入的<SampleData>
// 只获取object的meta,不获取内容
ObjectMetadata objectMetadata = client.GetObjectMetadata(bucketName, objectName);
Console.WriteLine(objectMetadata.ContentLength);
Console.ReadKey();
// 生成url,并通过该url直接下载和打印对象内容
string url = client.GeneratePresignedUrl(bucketName, objectName, 60).AbsoluteUri;
using (WebClient webClient = new WebClient())
{
using (Stream stream = webClient.OpenRead(url))
using (StreamReader streamReader = new StreamReader(stream))
{
string response = streamReader.ReadToEnd();
Console.WriteLine(response); // 您传入的<SampleData>
}
}
}
private static BosClient GenerateBosClient()
{
const string accessKeyId = <AccessKeyID>; // 您的Access Key ID
const string secretAccessKey = <SecretAccessKey>; // 您的Secret Access Key
const string endpoint = "https://bj.bcebos.com"; // 指定BOS服务域名
// 初始化一个BosClient
BceClientConfiguration config = new BceClientConfiguration();
config.Credentials = new DefaultBceCredentials(accessKeyId, secretAccessKey);
config.Endpoint = endpoint;
return new BosClient(config);
}
}
}
删除Object
-
基本流程
- 创建一个BOSClient类的实例。
- 调用BosClient.DeleteObject()方法。在调用该方法时你需要提供Bucket名称,Object名称等参数。
-
示例代码
public void DeleteObject(BosClient client, string bucketName, string objectKey) { // 删除Object client.DeleteObject(bucketName, objectKey); }
-
完整示例
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text; using BaiduBce; using BaiduBce.Auth; using BaiduBce.Services.Bos; using BaiduBce.Services.Bos.Model; namespace DotnetSample { internal class DeleteObjectSample { private static void Main(string[] args) { BosClient client = GenerateBosClient(); const string bucketName = <BucketName>; //指定Bucket名称 // 初始化:创建示例Bucket和Object client.CreateBucket(bucketName); string objectName = <ObjectKey>; client.PutObject(bucketName, objectName, <Sampledata>); // 删除Object client.DeleteObject(bucketName, objectName); } private static BosClient GenerateBosClient() { const string accessKeyId = <AccessKeyID>; // 您的Access Key ID const string secretAccessKey = <SecretAccessKey>; // 您的Secret Access Key const string endpoint = "https://bj.bcebos.com"; // 指定BOS服务域名 // 初始化一个BosClient BceClientConfiguration config = new BceClientConfiguration(); config.Credentials = new DefaultBceCredentials(accessKeyId, secretAccessKey); config.Endpoint = endpoint; return new BosClient(config); } } }
拷贝Object
简单拷贝Object
-
基本流程
- 创建BOSClient 类的实例。
- 执行BOSClient.copyObject( )方法。
-
示例代码
public void CopyObject(BosClient client, String srcBucketName, String srcKey, String destBucketName, String destKey) { // 拷贝Object CopyObjectResponse copyObjectResponse = client.CopyObject(srcBucketName, srcKey, destBucketName, destKey); // 打印结果 Console.WriteLine("ETag: " + copyObjectResponse.ETag + " LastModified: " + copyObjectResponse.LastModified); }
说明:copyObject 方法返回一个
CopyObjectResponse
对象,该对象中包含了新Object的ETag和修改时间。 -
完整示例
请参考完整示例。
通过CopyObjectRequest拷贝Object
您也可以通过 CopyObjectRequest
实现Object的拷贝。该功能一般用于如下场景:
- Copy一个Object但重新设置meta。
- 重置某个现有Object的meta(把Src和Des设置为同一个Object)。
-
基本流程
- 创建CopyObjectRequest类的实例,传入
<SrcBucketName>
,<SrcKey>
,<DestBucketName>
,<DestKey>
参数。 - 创建ObjectMetadata类的实例。
- 创建CopyObjectRequest类的实例,传入
-
示例代码
// 初始化BosClient BosClient client = ...; // 创建CopyObjectRequest对象 CopyObjectRequest copyObjectRequest = new CopyObjectRequest() { SourceBucketName = srcBucketName, SourceKey = srcKey, BucketName = destBucketName, Key = destKey }; // 设置新的Metadata Dictionary<String, String> userMetadata = new Dictionary<String, String>(); userMetadata["usermetakey"] = "usermetavalue"; ObjectMetadata objectMetadata = new ObjectMetadata() { UserMetadata = userMetadata }; copyObjectRequest.NewObjectMetadata = objectMetadata; // 复制Object并打印新的ETag CopyObjectResponse copyObjectResponse = client.CopyObject(copyObjectRequest); Console.WriteLine("ETag: " + copyObjectResponse.ETag + " LastModified: " + copyObjectResponse.LastModified);
说明:
CopyObjectRequest
允许用户修改目的Object的ObjectMeta,同时也提供MatchingETagConstraints
参数的设定。 -
完整示例
请参考完整示例。
完整示例
下面示例代码演示了简单拷贝Object和通过CopyObjectRequest拷贝Object的完整过程:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using BaiduBce;
using BaiduBce.Auth;
using BaiduBce.Services.Bos;
using BaiduBce.Services.Bos.Model;
namespace DotnetSample
{
internal class CopyObjectSample
{
private static void Main(string[] args)
{
BosClient client = GenerateBosClient();
const string bucketName = <SrcBucketName>;
// 初始化,创建示例Bucket和Object
client.CreateBucket(bucketName);
string objectName = <SrcObjectKey>;
client.PutObject(bucketName, objectName, <SrcSampleData>);
// 普通拷贝并打印结果
string newObjectName = <DesObjectKey>;
CopyObjectResponse copyObjectResponse = client.CopyObject(bucketName, objectName, bucketName,
newObjectName);
Console.WriteLine(Encoding.Default.GetString(client.GetObjectContent(bucketName, newObjectName)));
// 拷贝并设置新的meta
newObjectName = <DesObjectKey>;
CopyObjectRequest copyObjectRequest = new CopyObjectRequest()
{
SourceBucketName = bucketName,
SourceKey = objectName,
BucketName = bucketName,
Key = newObjectName
};
Dictionary<String, String> userMetadata = new Dictionary<String, String>();
userMetadata["usermetakey"] = "usermetavalue";
ObjectMetadata objectMetadata = new ObjectMetadata()
{
UserMetadata = userMetadata
};
copyObjectRequest.NewObjectMetadata = objectMetadata;
client.CopyObject(copyObjectRequest);
// usermetavalue
Console.WriteLine(client.GetObjectMetadata(bucketName, newObjectName).UserMetadata["usermetakey"]);
}
private static BosClient GenerateBosClient()
{
const string accessKeyId = <AccessKeyID>; // 您的Access Key ID
const string secretAccessKey = <SecretAccessKey>; // 您的Secret Access Key
const string endpoint = "https://bj.bcebos.com"; // 指定BOS服务域名
// 初始化一个BosClient
BceClientConfiguration config = new BceClientConfiguration();
config.Credentials = new DefaultBceCredentials(accessKeyId, secretAccessKey);
config.Endpoint = endpoint;
return new BosClient(config);
}
}
}
Object的分块上传
除了通过putObject()方法上传文件到BOS以外,BOS还提供了另外一种上传模式:分块上传(Multipart Upload)。用户可以在如下的应用场景内(但不仅限于此),使用分块上传模式,如:
- 需要支持断点上传。
- 上传超过5GB大小的文件。
- 网络条件较差,和BOS的服务器之间的连接经常断开。
- 需要流式地上传文件。
- 上传文件之前,无法确定上传文件的大小。
分块完成Multipart Upload
假设有一个文件,本地路径为 d:\\sample.txt
,由于文件比较大,将其分块传输到BOS中。
-
基本流程
- 创建一个BOSClient类的实例。
- 调用BosClient.InitiateMultipartUpload()方法。在调用该方法时您需要提供Bucket名称和Object名称,该方法会返回一个UploadId,在后面的步骤中需要用到该Id。
- 多次调用调用BosClient.UploadPart方法将文件分块多次上传。调用该方法时您需要提供Bucket名称,Object名称,UploadId,分块序号,分块大小,分块内容等参数,每次调用该方法都会返回本次分块的序号和ETag,在后面的步骤中会用到。
- 调用BosClient.CompleteMultipartUpload()方法完成本次分块上传。调用该方法您需要提供Bucket名称,Object名称,UploadId以及每个分块的序号和ETag。
- 上传过程中可以通过BosClient.ListParts()方法获取指定UploadId中已经上传的所有块;还可以通过BosClient.ListMultipartUploads()方法获取指定Bucket中所有未完成的UploadId。
初始化Multipart Upload
使用 InitiateMultipartUpload
方法来初始化一个分块上传事件:
-
示例代码
// 开始Multipart Upload InitiateMultipartUploadRequest initiateMultipartUploadRequest = new InitiateMultipartUploadRequest() {BucketName = bucketName, Key = objectKey}; InitiateMultipartUploadResponse initiateMultipartUploadResponse = client.InitiateMultipartUpload(initiateMultipartUploadRequest); // 打印UploadId Console.WriteLine("UploadId: " + initiateMultipartUploadResponse.UploadId);
说明:
initiateMultipartUpload
的返回结果中含有UploadId
,它是区分分块上传事件的唯一标识,在后面的操作中,我们将用到它。
上传分块
把文件分块上传。
-
示例代码
// 设置每块为 5Mb long partSize = 1024 * 1024 * 5L; FileInfo partFile = new FileInfo("my file"); // 计算分块数目 int partCount = (int) (partFile.Length / partSize); if (partFile.Length % partSize != 0) { partCount++; } // 新建一个List保存每个分块上传后的ETag和PartNumber List<PartETag> partETags = new List<PartETag>(); for (int i = 0; i < partCount; i++) { // 获取文件流 Stream stream = partFile.OpenRead(); // 跳到每个分块的开头 long skipBytes = partSize * i; stream.Seek(skipBytes, SeekOrigin.Begin); // 计算每个分块的大小 long size = Math.Min(partSize, partFile.Length - skipBytes); // 创建UploadPartRequest,上传分块 uploadPartRequest uploadPartRequest = new UploadPartRequest(); uploadPartRequest.BucketName = bucketName; uploadPartRequest.Key = objectKey; uploadPartRequest.UploadId = initiateMultipartUploadResponse.UploadId; uploadPartRequest.InputStream = stream; uploadPartRequest.PartSize = size; uploadPartRequest.PartNumber = i + 1; UploadPartResponse uploadPartResponse = client.UploadPart(uploadPartRequest); // 将返回的PartETag保存到List中。 partETags.Add(new PartETag() { ETag = uploadPartResponse.ETag, PartNumber = uploadPartResponse.PartNumber }); // 关闭文件 stream.Close(); }
注意:
上面代码的核心是调用
UploadPart
方法来上传每一个分块,但是要注意以下几点:- 分块上传方法要求除最后一个Part以外,其他的Part大小都要大于等于5MB。但是Upload Part接口并不会检查上传Part的大小;只有当Complete Multipart Upload的时候才会校验。
- 为了保证数据在网络传输过程中不出现错误,建议您在
UploadPart
后,使用每个分块BOS返回的Content-MD5值分别验证已上传分块数据的正确性。当所有分块数据合成一个Object后,不再含MD5值。 - Part号码的范围是1~10000。如果超出这个范围,BOS将返回InvalidArgument的错误码。
- 每次上传Part时都要把流定位到此次上传块开头所对应的位置。
- 每次上传Part之后,BOS的返回结果会包含一个
PartETag
对象,它是上传块的ETag与块编号(PartNumber)的组合,在后续完成分块上传的步骤中会用到它,因此需要将其保存起来。一般来讲这些PartETag
对象将被保存到List中。
完成分块上传
-
示例代码
CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest() { BucketName = bucketName, Key = objectKey, UploadId = initiateMultipartUploadResponse.UploadId, PartETags = partETags }; // 完成分块上传 CompleteMultipartUploadResponse completeMultipartUploadResponse = client.CompleteMultipartUpload(completeMultipartUploadRequest); // 打印Object的ETag Console.WriteLine(completeMultipartUploadResponse.ETag);
说明:上面代码中的
partETags
是第二部中保存的partETag的列表,BOS收到用户提交的Part列表后,会逐一验证每个数据Part的有效性。当所有的数据Part验证通过后,BOS将把这些数据part组合成一个完整的Object。
取消分块上传事件
用户可以使用abortMultipartUpload方法取消分块上传。
-
示例代码
AbortMultipartUploadRequest abortMultipartUploadRequest = new AbortMultipartUploadRequest() { BucketName = bucketName, Key = objectKey, UploadId = initiateMultipartUploadResponse.UploadId, }; // 取消分块上传 client.AbortMultipartUpload(abortMultipartUploadRequest);
获取未完成的分块上传事件
用户可以使用 ListMultipartUploads
方法获取Bucket内未完成的分块上传事件。
-
示例代码
ListMultipartUploadsRequest listMultipartUploadsRequest = new ListMultipartUploadsRequest() {BucketName = bucketName}; // 获取Bucket内所有上传事件 ListMultipartUploadsResponse listMultipartUploadsResponse = client.ListMultipartUploads(listMultipartUploadsRequest); // 遍历所有上传事件 foreach (MultipartUploadSummary multipartUpload in listMultipartUploadsResponse.Uploads) { Console.WriteLine("Key: " + multipartUpload.Key + " UploadId: " + multipartUpload.UploadId); }
注意:
- 默认情况下,如果Bucket中的分块上传事件的数目大于1000,则只会返回1000个,并且返回结果中IsTruncated的值为True,同时返回NextKeyMarker作为下次读取的起点。
- 若想获取更多分块上传事件,可以使用KeyMarker参数分次读取。
获取所有已上传的块信息
用户可以使用 ListParts
方法获取某个上传事件中所有已上传的块。
-
示例代码
ListPartsRequest listPartsRequest = new ListPartsRequest() { BucketName = bucketName, Key = objectKey, UploadId = initiateMultipartUploadResponse.UploadId, }; // 获取上传的所有Part信息 ListPartsResponse listPartsResponse = client.ListParts(listPartsRequest); // 遍历所有Part foreach (PartSummary part in listPartsResponse.Parts) { Console.WriteLine("PartNumber: " + part.PartNumber + " ETag: " + part.ETag); }
注意:
- 默认情况下,如果Bucket中的分块上传事件的数目大于1000,则只会返回1000个part,并且返回结果中IsTruncated的值为True,同时返回NextPartNumberMarker作为下次读取的起点。
- 若想获取更多已上传的分块信息,可以使用PartNumberMarker参数分次读取。
完整示例
下面示例代码演示了分块上传的完整过程:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using BaiduBce;
using BaiduBce.Auth;
using BaiduBce.Services.Bos;
using BaiduBce.Services.Bos.Model;
namespace DotnetSample
{
internal class MultiUploadSample
{
private static void Main(string[] args)
{
BosClient client = GenerateBosClient();
const string bucketName = <BucketName>; //Bucket名称
// 初始化:创建示例Bucket
client.CreateBucket(bucketName);
string objectKey = <ObjectKey>;
// 开始Multipart Upload
InitiateMultipartUploadRequest initiateMultipartUploadRequest =
new InitiateMultipartUploadRequest() { BucketName = bucketName, Key = objectKey };
InitiateMultipartUploadResponse initiateMultipartUploadResponse =
client.InitiateMultipartUpload(initiateMultipartUploadRequest);
// 获取Bucket内的Multipart Upload
ListMultipartUploadsRequest listMultipartUploadsRequest =
new ListMultipartUploadsRequest() { BucketName = bucketName };
ListMultipartUploadsResponse listMultipartUploadsResponse =
client.ListMultipartUploads(listMultipartUploadsRequest);
foreach (MultipartUploadSummary multipartUpload in listMultipartUploadsResponse.Uploads)
{
Console.WriteLine("Key: " + multipartUpload.Key + " UploadId: " + multipartUpload.UploadId);
}
// 分块上传,首先设置每块为 5Mb
long partSize = 1024 * 1024 * 5L;
FileInfo partFile = new FileInfo("d:\\lzb\\sample");
// 计算分块数目
int partCount = (int)(partFile.Length / partSize);
if (partFile.Length % partSize != 0)
{
partCount++;
}
// 新建一个List保存每个分块上传后的ETag和PartNumber
List<PartETag> partETags = new List<PartETag>();
for (int i = 0; i < partCount; i++)
{
// 获取文件流
Stream stream = partFile.OpenRead();
// 跳到每个分块的开头
long skipBytes = partSize * i;
stream.Seek(skipBytes, SeekOrigin.Begin);
// 计算每个分块的大小
long size = Math.Min(partSize, partFile.Length - skipBytes);
// 创建UploadPartRequest,上传分块
UploadPartRequest uploadPartRequest = new UploadPartRequest();
uploadPartRequest.BucketName = bucketName;
uploadPartRequest.Key = objectKey;
uploadPartRequest.UploadId = initiateMultipartUploadResponse.UploadId;
uploadPartRequest.InputStream = stream;
uploadPartRequest.PartSize = size;
uploadPartRequest.PartNumber = i + 1;
UploadPartResponse uploadPartResponse = client.UploadPart(uploadPartRequest);
// 将返回的PartETag保存到List中。
partETags.Add(new PartETag()
{
ETag = uploadPartResponse.ETag,
PartNumber = uploadPartResponse.PartNumber
});
// 关闭文件
stream.Close();
}
// 获取UploadId的所有Upload Part
ListPartsRequest listPartsRequest = new ListPartsRequest()
{
BucketName = bucketName,
Key = objectKey,
UploadId = initiateMultipartUploadResponse.UploadId,
};
// 获取上传的所有Part信息
ListPartsResponse listPartsResponse = client.ListParts(listPartsRequest);
// 遍历所有Part
foreach (PartSummary part in listPartsResponse.Parts)
{
Console.WriteLine("PartNumber: " + part.PartNumber + " ETag: " + part.ETag);
}
// 完成分块上传
CompleteMultipartUploadRequest completeMultipartUploadRequest =
new CompleteMultipartUploadRequest()
{
BucketName = bucketName,
Key = objectKey,
UploadId = initiateMultipartUploadResponse.UploadId,
PartETags = partETags
};
CompleteMultipartUploadResponse completeMultipartUploadResponse =
client.CompleteMultipartUpload(completeMultipartUploadRequest);
Console.WriteLine(completeMultipartUploadResponse.ETag);
Console.ReadKey();
}
private static BosClient GenerateBosClient()
{
const string accessKeyId = <AccessKeyID>; // 您的Access Key ID
const string secretAccessKey = <SecretAccessKey>; // 您的Secret Access Key
const string endpoint = "https://bj.bcebos.com"; // 指定BOS服务域名
// 初始化一个BosClient
BceClientConfiguration config = new BceClientConfiguration();
config.Credentials = new DefaultBceCredentials(accessKeyId, secretAccessKey);
config.Endpoint = endpoint;
return new BosClient(config);
}
}
}
支持单链接限速
对象存储BOS对单Bucket的公网带宽阈值为10Gbit/s,内网带宽阈值为50Gbit/s,当用户的上传或下载占用带宽达到带宽限制阈值时,会返回RequestRateLimitExceeded的错误码。为保证用户能够正常使用服务,BOS支持在进行上传、下载等行为时进行流量控制,保证大流量服务占用带宽不会对其他应用服务造成影响。
单链接限速上传和下载接口示例
限速值的取值范围为819200~838860800,单位为bit/s,即100KB/s~100MB/s。限速值取值必须为数字,BOS将按照指定的限速值对此次请求进行限速,当限速值不在此范围或不合法时将返回400错误码。
public void ObjectTrafficLimit(BosClient client, String bucketName, String objectKey, byte[] byte1, String string1)
{
// 具体的限速值
long trafficLimit = 819200;
// 获取指定文件
FileInfo file = new FileInfo(<FilePath>); //指定文件路径
// 生成put请求
PutObjectRequest putRequest = new PutObjectRequest()
{
BucketName = bucketName,
Key = objectKey,
FileInfo = file,
TrafficLimit = trafficLimit
};
// 以文件形式上传Object
PutObjectResponse putObjectFromFileResponse = client.PutObject(putRequest);
// 打印ETag
Console.WriteLine(putObjectFromFileResponse.ETAG);
// 生成get请求
GetObjectRequest getRequest = new GetObjectRequest()
{
BucketName = bucketName,
Key = objectKey,
TrafficLimit = trafficLimit
};
// 获取object
BosObject bosObject = client.GetObject(getRequest);
// 打印ETag
Console.WriteLine(bosObject.ObjectMetadata.ETag);
}