全部产品
存储与CDN 数据库 安全 应用服务 数加·人工智能 数加·大数据基础服务 互联网中间件 视频服务 开发者工具 解决方案 物联网
对象存储 OSS

管理文件

更新时间:2017-06-12 15:24:36

在OSS中,用户可以通过一系列的接口管理存储空间(Bucket)中的文件(Object),比如ListObjects、DeleteObject、CopyObject、DoesObjectExist等。

列出存储空间中的文件

简单列出文件

  1. using Aliyun.OSS;
  2. // 初始化OssClient
  3. var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
  4. /// <summary>
  5. /// 列出指定存储空间下的文件的摘要信息OssObjectSummary列表
  6. /// </summary>
  7. /// <param name="bucketName">存储空间的名称</param>
  8. public void ListObjects(string bucketName)
  9. {
  10. try
  11. {
  12. var listObjectsRequest = new ListObjectsRequest(bucketName);
  13. var result = client.ListObjects(listObjectsRequest);
  14. Console.WriteLine("List objects succeeded");
  15. foreach (var summary in result.ObjectSummaries)
  16. {
  17. Console.WriteLine("File name:{0}", summary.Key);
  18. }
  19. }
  20. catch (Exception ex)
  21. {
  22. Console.WriteLine("List objects failed. {0}", ex.Message);
  23. }
  24. }

说明:

  • 完整代码参考GitHub
  • 默认情况下,如果存储空间中的文件数量大于100,则只会返回100个文件, 且返回结果中 IsTruncated 为 true,并返回 NextMarker 作为下此读取的起点。
  • 若想增大返回文件数目,可以修改MaxKeys参数,或者使用Marker参数分次读取。

带前缀过滤的列出文件

  1. using Aliyun.OSS;
  2. // 初始化OssClient
  3. var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
  4. /// <summary>
  5. /// 列出指定存储空间下其Key以prefix为前缀的文件的摘要信息OssObjectSummary
  6. /// </summary>
  7. /// <param name="bucketName">存储空间的名称</param>
  8. /// <param name="prefix">限定返回的文件必须以此作为前缀</param>
  9. public void ListObjects(string bucketName, string prefix)
  10. {
  11. try
  12. {
  13. var listObjectsRequest = new ListObjectsRequest(bucketName)
  14. {
  15. Prefix = prefix
  16. };
  17. var result = client.ListObjects(listObjectsRequest);
  18. Console.WriteLine("List objects succeeded");
  19. foreach (var summary in result.ObjectSummaries)
  20. {
  21. Console.WriteLine("File Name:{0}", summary.Key);
  22. }
  23. }
  24. catch (Exception ex)
  25. {
  26. Console.WriteLine("List objects failed. {0}", ex.Message);
  27. }
  28. }

通过异步方式列出文件

  1. using Aliyun.OSS;
  2. // 初始化OssClient
  3. static OssClient ossClient = new OssClient(endpoint, accessKeyId, accessKeySecret);
  4. static AutoResetEvent _event = new AutoResetEvent(false);
  5. public static void AsyncListObjects()
  6. {
  7. try
  8. {
  9. var listObjectsRequest = new ListObjectsRequest(bucketName);
  10. ossClient.BeginListObjects(listObjectsRequest, ListObjectCallback, null);
  11. _event.WaitOne();
  12. }
  13. catch (Exception ex)
  14. {
  15. Console.WriteLine("List objects failed. {0}", ex.Message);
  16. }
  17. }
  18. private static void ListObjectCallback(IAsyncResult ar)
  19. {
  20. try
  21. {
  22. var result = ossClient.EndListObjects(ar);
  23. foreach (var summary in result.ObjectSummaries)
  24. {
  25. Console.WriteLine("文件名称:{0}", summary.Key);
  26. }
  27. _event.Set();
  28. Console.WriteLine("List objects succeeded");
  29. }
  30. catch (Exception ex)
  31. {
  32. Console.WriteLine("List objects failed. {0}", ex.Message);
  33. }
  34. }

说明:

  • 完整代码参考GitHub
  • 上面的ListObjectCallback方法就是异步调用结束后执行的回调方法,如果使用异步类型的接口,都需要实现类似接口。

通过ListObjectsRequest列出文件

我们可以通过设置ListObjectsRequest的参数来完成更强大的功能。比如:

  1. using Aliyun.OSS;
  2. // 初始化OssClient
  3. var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
  4. /// <summary>
  5. /// 列出指定存储空间下的文件的摘要信息OssObjectSummary列表
  6. /// </summary>
  7. /// <param name="bucketName">存储空间的名称</param>
  8. public void ListObjects(string bucketName)
  9. {
  10. try
  11. {
  12. var listObjectsRequest = new ListObjectsRequest(bucketName)
  13. {
  14. Delimiter = "/",
  15. Marker = "abc"
  16. };
  17. result = client.ListObjects(listObjectsRequest);
  18. Console.WriteLine("List objects succeeded");
  19. foreach (var summary in result.ObjectSummaries)
  20. {
  21. Console.WriteLine("文件名称:{0}", summary.Key);
  22. }
  23. }
  24. catch (Exception ex)
  25. {
  26. Console.WriteLine("List objects failed. {0}", ex.Message);
  27. }
  28. }

可以设置的参数名称和作用如下:

名称 作用
Delimiter 用于对文件名字进行分组的字符。所有名字包含指定的前缀且第一次出现Delimiter字符之间的文件作为一组元素: CommonPrefixes。
Marker 设定结果从Marker之后按字母排序的第一个开始返回。
MaxKeys 限定此次返回文件的最大数,如果不设定,默认为100,MaxKeys取值不能大于1000。
Prefix 限定返回的文件名称必须以Prefix作为前缀。注意使用Prefix查询时,返回的文件名中仍会包含Prefix。

说明:

  • 完整代码参考GitHub
  • 如果需要遍历所有的文件,而文件数量大于100,则需要进行多次迭代。每次迭代时,将上次迭代列取最后一个文件的key作为本次迭代中的Marker即可。

文件夹功能模拟

我们还可以通过 Delimiter 和 Prefix 参数的配合模拟出文件夹功能。Delimiter 和 Prefix 的组合效果是这样的:

  • 如果把 Prefix 设为某个文件夹名,就可以罗列以此 Prefix 开头的文件,即该文件夹下递归的所有的文件和子文件夹。
  • 如果再把 Delimiter 设置为“/”时,返回值就只罗列该文件夹下的文件,该文件夹下的子文件夹返回在 CommonPrefixes 部分,子文件夹下递归的文件和文件夹不被显示。假设Bucket中有4个文件: oss.jpg、fun/test.jpg、fun/movie/001.avi、fun/movie/007.avi ,我们把“/”符号作为文件夹的分隔符。

列出存储空间内所有文件

当我们需要获取存储空间下的所有文件时,可以这样写:

  1. using Aliyun.OSS;
  2. // 初始化OssClient
  3. var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
  4. public void ListObject(string bucketName)
  5. {
  6. try
  7. {
  8. ObjectListing result = null;
  9. string nextMarker = string.Empty;
  10. do
  11. {
  12. var listObjectsRequest = new ListObjectsRequest(bucketName)
  13. {
  14. Marker = nextMarker,
  15. MaxKeys = 100
  16. };
  17. result = client.ListObjects(listObjectsRequest);
  18. Console.WriteLine("File:");
  19. foreach (var summary in result.ObjectSummaries)
  20. {
  21. Console.WriteLine("Name:{0}", summary.Key);
  22. }
  23. nextMarker = result.NextMarker;
  24. } while (result.IsTruncated);
  25. }
  26. catch (Exception ex)
  27. {
  28. Console.WriteLine("List object failed. {0}", ex.Message);
  29. }
  30. }

输出:

  1. File:
  2. Name:fun/movie/001.avi
  3. Name:fun/movie/007.avi
  4. Name:fun/test.jpg
  5. Name:oss.jpg

递归列出目录下所有文件

我们可以通过设置 Prefix 参数来获取某个目录下所有的文件:

  1. using Aliyun.OSS;
  2. // 初始化OssClient
  3. var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
  4. public void ListObject(string bucketName)
  5. {
  6. try
  7. {
  8. var listObjectsRequest = new ListObjectsRequest(bucketName)
  9. {
  10. Prefix = "fun/"
  11. };
  12. result = client.ListObjects(listObjectsRequest);
  13. Console.WriteLine("List object succeeded");
  14. Console.WriteLine("File:");
  15. foreach (var summary in result.ObjectSummaries)
  16. {
  17. Console.WriteLine("Name:{0}", summary.Key);
  18. }
  19. Console.WriteLine("Dir:");
  20. foreach (var prefix in result.CommonPrefixes)
  21. {
  22. Console.WriteLine("Name:{0}", prefix);
  23. }
  24. }
  25. catch (Exception ex)
  26. {
  27. Console.WriteLine("List object failed. {0}", ex.Message);
  28. }
  29. }

输出:

  1. List object succeeded
  2. File:
  3. Name:fun/movie/001.avi
  4. Name:fun/movie/007.avi
  5. Name:fun/test.jpg
  6. 目录:

列出目录下的文件和子目录

在 Prefix 和 Delimiter 结合的情况下,可以列出目录下的文件和子目录:

  1. using Aliyun.OSS;
  2. // 初始化OssClient
  3. var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
  4. public void ListObjects(string bucketName)
  5. {
  6. try
  7. {
  8. var listObjectsRequest = new ListObjectsRequest(bucketName)
  9. {
  10. Prefix = "fun/",
  11. Delimiter = "/"
  12. };
  13. result = client.ListObjects(listObjectsRequest);
  14. Console.WriteLine("List object succeeded");
  15. Console.WriteLine("File:");
  16. foreach (var summary in result.ObjectSummaries)
  17. {
  18. Console.WriteLine("Name:{0}", summary.Key);
  19. }
  20. Console.WriteLine("Dir:");
  21. foreach (var prefix in result.CommonPrefixes)
  22. {
  23. Console.WriteLine("Name:{0}", prefix);
  24. }
  25. }
  26. catch (Exception ex)
  27. {
  28. Console.WriteLine("List object failed. {0}", ex.Message);
  29. }
  30. }

输出:

  1. List object success
  2. File:
  3. Name:fun/test.jpg
  4. Dir:
  5. Name:fun/movie/

说明:

  • 返回的结果中, ObjectSummaries 的列表中给出的是fun目录下的文件。
  • 而 CommonPrefixs 的列表中给出的是fun目录下的所有子文件夹。可以看出 fun/movie/001.avifun/movie/007.avi 两个文件并没有被列出来,因为它们属于fun文件夹下的movie目录。

删除文件

删除一个文件

  1. using Aliyun.OSS;
  2. // 初始化OssClient
  3. var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
  4. /// <summary>
  5. /// 列出指定存储空间下的特定文件
  6. /// </summary>
  7. /// <param name="bucketName">存储空间的名称</param>
  8. /// <param name="key">文件的名称</param>
  9. public void DeleteObject(string bucketName, string key)
  10. {
  11. try
  12. {
  13. client.DeleteObject(bucketName, key);
  14. Console.WriteLine("Delete object succeeded");
  15. }
  16. catch (Exception ex)
  17. {
  18. Console.WriteLine("Delete object failed. {0}", ex.Message);
  19. }
  20. }

说明: 完整代码参考GitHub

删除多个文件

  1. using Aliyun.OSS;
  2. // 初始化OssClient
  3. var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
  4. /// <summary>
  5. /// 删除指定存储空间中的所有文件
  6. /// </summary>
  7. /// <param name="bucketName">存储空间的名称</param>
  8. public void DeleteObjects(string bucketName)
  9. {
  10. try
  11. {
  12. var keys = new List<string>();
  13. var listResult = client.ListObjects(bucketName);
  14. foreach (var summary in listResult.ObjectSummaries)
  15. {
  16. keys.Add(summary.Key);
  17. }
  18. var request = new DeleteObjectsRequest(bucketName, keys, false);
  19. client.DeleteObjects(request);
  20. Console.WriteLine("Delete objects succeeded");
  21. }
  22. catch (Exception ex)
  23. {
  24. Console.WriteLine("Delete objects failed. {0}", ex.Message);
  25. }
  26. }

说明: 完整代码参考GitHub

拷贝文件

在同一个区域(杭州,深圳,青岛等)中,用户可以对有操作权限的文件进行复制操作。

拷贝一个文件

通过 copyObject 方法我们可以拷贝一个文件,代码如下:

  1. using Aliyun.OSS;
  2. // 初始化OssClient
  3. var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
  4. /// <summary>
  5. /// 拷贝文件
  6. /// </summary>
  7. /// <param name="sourceBucket">原文件所在存储空间的名称</param>
  8. /// <param name="sourceKey">原文件的名称</param>
  9. /// <param name="targetBucket">目标文件所在存储空间的名称</param>
  10. /// <param name="targetKey">目标文件的名称</param>
  11. public void CopyObect(string sourceBucket, string sourceKey, string targetBucket, string targetKey)
  12. {
  13. try
  14. {
  15. var metadata = new ObjectMetadata();
  16. metadata.AddHeader(Util.HttpHeaders.ContentType, "text/html");
  17. var req = new CopyObjectRequest(sourceBucket, sourceKey, targetBucket, targetKey)
  18. {
  19. NewObjectMetadata = metadata
  20. };
  21. var ret = client.CopyObject(req);
  22. Console.WriteLine("Copy object succeeded");
  23. Console.WriteLine("文件的ETag:{0}", ret.ETag);
  24. }
  25. catch (Exception ex)
  26. {
  27. Console.WriteLine("Copy object failed. {0}", ex.Message);
  28. }
  29. }

说明:

  • 完整代码参考GitHub
  • 使用该方法拷贝的文件必须小于1G,否则会报错。若文件大于1G,使用下面的Upload Part Copy。

拷贝大文件

初始化Multipart Upload

我们使用 initiateMultipartUpload 方法来初始化一个分片上传事件:

  1. using Aliyun.OSS;
  2. // 初始化OssClient
  3. var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
  4. public void InitiateMultipartUpload(string bucketName, string key)
  5. {
  6. try
  7. {
  8. // 开始Multipart Upload
  9. var request = new InitiateMultipartUploadRequest(bucketName, key);
  10. var result = client.InitiateMultipartUpload(request);
  11. // 打印UploadId
  12. Console.WriteLine("Init multipart upload succeeded");
  13. Console.WriteLine("Upload Id:{0}", result.UploadId);
  14. }
  15. catch (Exception ex)
  16. {
  17. Console.WriteLine("Init multipart upload failed. {0}", ex.Message);
  18. }
  19. }

说明: 完整代码参考GitHub

Upload Part Copy拷贝上传

Upload Part Copy 通过从一个已经存在文件的中拷贝数据来上传一个新文件。当拷贝一个大于500MB的文件,建议使用Upload Part Copy的方式来进行拷贝。

  1. using Aliyun.OSS;
  2. // 初始化OssClient
  3. var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
  4. public void UploadPartCopy(string sourceBucket, string sourceKey, string targetBucket, string targetKey, string uploadId)
  5. {
  6. try
  7. {
  8. // 计算总共的分片个数
  9. var metadata = client.GetObjectMetadata(sourceBucket, sourceKey);
  10. var fileSize = metadata.ContentLength;
  11. var partCount = (int)fileSize / partSize;
  12. if (fileSize % partSize != 0)
  13. {
  14. partCount++;
  15. }
  16. // 开始分片拷贝
  17. var partETags = new List<PartETag>();
  18. for (var i = 0; i < partCount; i++)
  19. {
  20. var skipBytes = (long)partSize * i;
  21. var size = (partSize < fileSize - skipBytes) ? partSize : (fileSize - skipBytes);
  22. var request = new UploadPartCopyRequest(targetBucket, targetKey, sourceBucket, sourceKey, uploadId)
  23. {
  24. PartSize = size,
  25. PartNumber = i + 1,
  26. BeginIndex = skipBytes
  27. };
  28. var result = client.UploadPartCopy(request);
  29. partETags.Add(result.PartETag);
  30. }
  31. Console.WriteLine("Upload part copy succeeded");
  32. }
  33. catch (Exception ex)
  34. {
  35. Console.WriteLine("Upload part copy failed. {0}", ex.Message);
  36. }

说明:

  • 完整代码参考GitHub
  • 以上程序调用uploadPartCopy方法来拷贝每一个分片。
  • 与UploadPart要求基本一致,需要通过BeginIndex来定位到此次上传片开头所对应的位置,同时需要通过SourceKey来指定拷贝的文件。

完成分片上传

完成分片上传代码如下:

  1. using Aliyun.OSS;
  2. // 初始化OssClient
  3. var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
  4. public void CompleteMultipartUpload(string bucketName, string key, string uploadId)
  5. {
  6. try
  7. {
  8. var completeMultipartUploadRequest = new CompleteMultipartUploadRequest(bucketName, key, uploadId);
  9. foreach (var partETag in partETags)
  10. {
  11. completeMultipartUploadRequest.PartETags.Add(partETag);
  12. }
  13. var result = client.CompleteMultipartUpload(completeMultipartUploadRequest);
  14. Console.WriteLine("Complete multipart upload succeeded");
  15. }
  16. catch (Exception ex)
  17. {
  18. Console.WriteLine("Complete multipart upload failed. {0}", ex.Message);
  19. }
  20. }

说明:

  • 完整代码参考GitHub
  • 上面代码中的 partETags 就是进行分片上传中保存的partETag的列表,OSS收到用户提交的Part列表后,会逐一验证每个数据Part的有效性。
  • 当所有的数据Part验证通过后,OSS会将这些part组合成一个完整的文件。

通过断点续传拷贝

除了支持分片拷贝外,还提供了断点续传功能,如果某次拷贝中断,下次可以从上次失败的位置开始拷贝,以便加快速度。

  1. using Aliyun.OSS;
  2. // 初始化OssClient
  3. var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
  4. public static void ResumableCopyObject(string sourceBucketName, string sourceKey,
  5. string destBucketName, string destKey)
  6. {
  7. string checkpointDir = @"<your checkpoint dir>";
  8. try
  9. {
  10. var request = new CopyObjectRequest(sourceBucketName, sourceKey, destBucketName, destKey);
  11. client.ResumableCopyObject(request, checkpointDir);
  12. Console.WriteLine("Resumable copy new object:{0} succeeded", request.DestinationKey);
  13. }
  14. catch (Exception ex)
  15. {
  16. Console.WriteLine("Resumable copy new object failed, {0}", ex.Message);
  17. }
  18. }

说明:

  • 完整代码参考GitHub
  • checkpointDir目录中会保存断点续传的中间状态,用于失败后,下次继续拷贝时使用。
  • 如果checkpointDir为null,断点续传功能不会生效,每次都会重新拷贝。

修改文件Meta

可以通过ModifyObjectMeta操作来实现修改已有文件的 meta 信息

  1. using Aliyun.OSS;
  2. // 初始化OssClient
  3. var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
  4. /// <summary>
  5. /// 修改文件的meta值
  6. /// </summary>
  7. /// <param name="bucketName">文件所在存储空间的名称</param>
  8. /// <param name="key">文件的名称</param>
  9. public void ModifyObjectMeta(string bucketName, string key)
  10. {
  11. try
  12. {
  13. var meta = new ObjectMetadata();
  14. meta.ContentType = "application/octet-stream";
  15. client.ModifyObjectMeta(bucketName, key, meta);
  16. Console.WriteLine("Modify object meta succeeded");
  17. }
  18. catch (Exception ex)
  19. {
  20. Console.WriteLine("Modify object meta failed. {0}", ex.Message);
  21. }
  22. }

说明: 完整代码参考GitHub

设置文件权限

文件权限的详细说明请参看权限控制,您可以通过SetBucketAcl设置文件权限。

  1. using Aliyun.OSS;
  2. // 初始化OssClient
  3. var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
  4. /// <summary>
  5. /// 设置文件权限
  6. /// </summary>
  7. /// <param name="bucketName">文件所在存储空间的名称</param>
  8. /// <param name="key">文件的名称</param>
  9. public void SetObjectAclSample(string bucketName, string key)
  10. {
  11. try
  12. {
  13. client.SetObjectAcl(bucketName, key, CannedAccessControlList.PublicRead);
  14. Console.WriteLine("Set Object:{0} Acl succeeded ", key);
  15. }
  16. catch (Exception ex)
  17. {
  18. Console.WriteLine("Failed with error info: {0}", ex.Message);
  19. }
  20. }

说明:

  • 文件的四种访问权限:private、public-read、public-read-write、default分别对应于CannedAccessControlList.Private、CannedAccessControlList.PublicRead、CannedAccessControlList.PublicReadWrite、CannedAccessControlList.Default。
  • 完整代码参考GitHub

读取文件权限

您可以通过GetBucketAcl读取文件权限。

  1. using Aliyun.OSS;
  2. // 初始化OssClient
  3. var client = new OssClient(endpoint, accessKeyId, accessKeySecret);
  4. /// <summary>
  5. /// 读取文件权限
  6. /// </summary>
  7. /// <param name="bucketName">文件所在存储空间的名称</param>
  8. /// <param name="key">文件的名称</param>
  9. public void SetObjectAclSample(string bucketName, string key)
  10. {
  11. try
  12. {
  13. var result = client.GetObjectAcl(bucketName, key);
  14. Console.WriteLine("Get Object Acl succeeded,Id:{0} Acl:{1} succeeded",
  15. result.Owner.Id, result.ACL.ToString());
  16. }
  17. catch (Exception ex)
  18. {
  19. Console.WriteLine("Failed with error info: {0}", ex.Message);
  20. }
  21. }

说明: 完整代码参考GitHub

本文导读目录