本篇内容主要记录.NET中使用MinIO文件存储的常用方法操作类,有关MioIO的概念和优缺点就不写了,百度都有。
MinIO文件服务器的搭建请查看:Java集成MinIO,项目中使用NuGet搜索MinIO进行安装即可。
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Minio;
using Minio.DataModel;
using Minio.Exceptions;
namespace ConsoleApplication1
{
public static class MinioHelper
{
static readonly string _endPoint = "127.0.0.1:9001";
static readonly string _accessKey = "minioadmin";
static readonly string _secretKey = "minioadmin";
static readonly bool _isSSL = false;
private static readonly MinioClient _minioClient = new MinioClient()
.WithEndpoint(_endPoint)
.WithCredentials(_accessKey,_secretKey)
.WithSSL(_isSSL)
.Build();
/// <summary>
/// 创建minio客户端连接
/// </summary>
/// <param name="endPoint">127.0.0.1:9001</param>
/// <param name="accessKey">minioadmin</param>
/// <param name="secretKey">minioadmin</param>
/// <param name="withSsl">是否是http</param>
/// <returns></returns>
public static MinioClient Create(string endPoint, string accessKey, string secretKey, bool withSsl = false)
{
MinioClient client = new MinioClient()
.WithEndpoint(endPoint)
.WithCredentials(accessKey,
secretKey);
if (withSsl)
{
client = client.WithSSL();
}
return client.Build();
}
#region 操作存储桶
/// <summary>
/// 创建存储桶
/// <example >
/// <code >
/// MinioHelper.MakeBucket(minio, buckName).Wait();
/// </code>
/// </example>
/// </summary>
/// <param name="bucketName">存储桶名称</param>
/// <param name = "loc" > 可选参数 </param >
/// <returns ></returns >
public static Task CreateBucket(string bucketName, string loc = "us-east-1")
{
try
{
bool found = BucketExists(bucketName);
if (found)
{
throw new Exception($"存储桶[{bucketName}]已存在");
}
MakeBucketArgs args = new MakeBucketArgs()
.WithBucket(bucketName)
.WithLocation(loc);
return _minioClient.MakeBucketAsync(args);
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
/// <summary>
/// 校验桶是否存在,如果不存在则报错
/// <example>
/// 调用示例
/// <code>
/// bool exists = MinioHelper.BucketExists(minio, buckName);
/// </code>
/// </example>
/// </summary>
/// <param name="bucketName"></param>
/// <exception cref="Exception"></exception>
public static void CheckBucket(string bucketName)
{
bool exists = BucketExists(bucketName);
if (!exists)
{
throw new BucketNotFoundException(bucketName, "存储桶不存在");
}
}
/// <summary>
/// 列出所有的存储桶
/// </summary>
/// <example>
/// <code>
/// abc</code>
/// </example>
/// <returns></returns>
public static ListAllMyBucketsResult ListBuckets()
{
Task<ListAllMyBucketsResult> data = _minioClient.ListBucketsAsync();
data.Wait();
return data.Result;
}
/// <summary>
/// 检查存储桶是否存在
/// </summary>
/// <example>
/// <code>
/// var data = MinioHelper.ListBuckets(minio);
/// </code>
/// </example>
/// <param name="bucketName">存储桶名称</param>
/// <param name="cancellationToken">取消标记</param>
/// <returns></returns>
public static bool BucketExists(string bucketName,
CancellationToken cancellationToken = default(CancellationToken))
{
try
{
BucketExistsArgs args = new BucketExistsArgs()
.WithBucket(bucketName);
Task<bool> bucketExistTask = _minioClient.BucketExistsAsync(args, cancellationToken);
Task.WaitAll(bucketExistTask);
return bucketExistTask.Result;
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
/// <summary>
/// 删除一个存储桶
/// </summary>
/// <param name="bucketName">存储桶名称</param>
/// <param name="cancellationToken">默认不填</param>
/// <returns></returns>
public static Task RemoveBucket(string bucketName,
CancellationToken cancellationToken = default(CancellationToken))
{
try
{
CheckBucket(bucketName);
RemoveBucketArgs args = new RemoveBucketArgs()
.WithBucket(bucketName);
return _minioClient.RemoveBucketAsync(args, cancellationToken);
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
/// <summary>列出存储桶里的对象
/// 列出存储桶里的对象
/// </summary>
/// <param name="bucketName">存储桶名称</param>
/// <param name="prefix">对象的前缀</param>
/// <param name="recursive">true代表递归查找,false代表类似文件夹查找,以'/'分隔,不查子文件夹</param>
public static IObservable<Item> ListObjects(string bucketName, string prefix = null,
bool recursive = true)
{
try
{
ListObjectsArgs args = new ListObjectsArgs()
.WithBucket(bucketName)
.WithPrefix(prefix)
.WithRecursive(recursive);
IObservable<Item> data = _minioClient.ListObjectsAsync(args);
return data;
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
#endregion
#region 操作文件对象
public static bool FileExist(string bucketName, string objectName)
{
try
{
var obj = new StatObjectArgs().WithBucket(bucketName)
.WithObject(objectName);
var objStat = _minioClient.StatObjectAsync(obj);
objStat.Wait();
}
catch (AggregateException e)
{
foreach (var item in e.InnerExceptions)
{
if (item is ObjectNotFoundException)
{
return false;
}
}
}
return true;
}
/// <summary>
/// 从桶下载文件到流
/// </summary>
/// <param name="bucketName">存储桶名称</param>
/// <param name="objectName">存储桶里的对象名称</param>
/// <param name="sse">默认不填</param>
/// <param name="cb">默认不填</param>
/// <returns></returns>
public static Task<ObjectStat> FGetObject(string bucketName, string objectName,
ServerSideEncryption sse = null, Action<Stream> cb = null)
{
CheckBucket(bucketName);
try
{
GetObjectArgs args = new GetObjectArgs()
.WithBucket(bucketName)
.WithObject(objectName)
.WithServerSideEncryption(sse)
.WithCallbackStream(cb);
return _minioClient.GetObjectAsync(args);
}
catch (MinioException e)
{
throw new Exception(e.Message);
}
}
/// <summary>
/// 从桶下载文件到本地
/// </summary>
/// <param name="bucketName"></param>
/// <param name="objectName"></param>
/// <param name="fileName"></param>
/// <param name="sse"></param>
/// <returns></returns>
public static Task<ObjectStat> FGetObject(string bucketName, string objectName,
string fileName,ServerSideEncryption sse = null)
{
CheckBucket(bucketName);
if (File.Exists(fileName))
{
File.Delete(fileName);
}
return FGetObject(bucketName, objectName, sse, stream =>
{
using (FileStream fileStream = new FileStream(fileName, FileMode.CreateNew, FileAccess.Write))
{
stream.CopyTo(fileStream);
}
});
}
/// <summary>
/// 上传本地文件至存储桶
/// </summary>
/// <param name="bucketName">存储桶名称</param>
/// <param name="objectName">存储桶里的对象名称</param>
/// <param name="fileName">本地路径</param>
/// <param name="contentType">contentType:默认不填</param>
/// <param name="metaData">metaData:默认不填</param>
/// <param name="sse">默认不填</param>
/// <returns></returns>
public static Task FPutObject(string bucketName, string objectName, string fileName,
string contentType = "application/octet-stream", Dictionary<string, string> metaData = null,
ServerSideEncryption sse = null)
{
CheckBucket(bucketName);
try
{
//var data= minio.PutObjectAsync(bucketName, objectName, fileName, contentType: "application/octet-stream");
PutObjectArgs args = new PutObjectArgs()
.WithBucket(bucketName)
.WithObject(objectName)
.WithFileName(fileName)
.WithContentType(contentType)
.WithHeaders(metaData)
.WithServerSideEncryption(sse);
return _minioClient.PutObjectAsync(args);
}
catch (MinioException e)
{
throw new Exception(e.Message);
}
}
#endregion
#region Presigned操作
/// <summary>生成一个给HTTP GET请求用的presigned URL。浏览器/移动端的客户端可以用这个URL进行下载,即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间,默认值是7天。
/// 生成一个给HTTP GET请求用的presigned URL。浏览器/移动端的客户端可以用这个URL进行下载,即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间,默认值是7天。
/// </summary>
/// <param name="bucketName">存储桶名称</param>
/// <param name="objectName">存储桶里的对象名称</param>
/// <param name="expiresInt">失效时间(以秒为单位),默认是7天,不得大于七天</param>
/// <returns></returns>
public static Task<string> PresignedGetObject(string bucketName, string objectName,
int expiresInt = 1000)
{
CheckBucket(bucketName);
try
{
//Dictionary<string, string> reqParams = new Dictionary<string, string> { { "response-content-type", "application/json" } };
PresignedGetObjectArgs args = new PresignedGetObjectArgs()
.WithBucket(bucketName)
.WithObject(objectName)
//.WithHeaders(reqParams)
.WithExpiry(expiresInt);
//.WithRequestDate(DateTime.Now.ToUniversalTime());
return _minioClient.PresignedGetObjectAsync(args);
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
/// <summary>
/// 生成一个给HTTP PUT请求用的presigned URL。浏览器/移动端的客户端可以用这个URL进行上传,即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间,默认值是7天。
/// </summary>
/// <param name="bucketName">存储桶名称</param>
/// <param name="objectName">存储桶里的对象名称</param>
/// <param name="expiresInt">失效时间(以秒为单位),默认是7天,不得大于七天</param>
/// <returns></returns>
public static Task<string> PresignedPutObject(string bucketName, string objectName,
int expiresInt = 1000)
{
CheckBucket(bucketName);
try
{
//string presignedUrl = await minio.PresignedPutObjectAsync(bucketName, objectName, expiresInt);
//Ret = presignedUrl;
//flag = true;
PresignedPutObjectArgs args = new PresignedPutObjectArgs()
.WithBucket(bucketName)
.WithObject(objectName)
.WithExpiry(expiresInt);
return _minioClient.PresignedPutObjectAsync(args);
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
/// <summary>
/// 允许给POST请求的presigned URL设置策略,比如接收对象上传的存储桶名称的策略,key名称前缀,过期策略。
/// </summary>
/// <param name="form">对象的post策略</param>
/// <returns></returns>
public static async Task<(Uri, Dictionary<string, string>)> PresignedPostPolicy(PostPolicy form)
{
try
{
//例如
//PostPolicy form = new PostPolicy();
//DateTime expiration = DateTime.UtcNow;
//form.SetExpires(expiration.AddDays(10));
//form.SetKey("my-objectname");
//form.SetBucket("my-bucketname");
(Uri, Dictionary<string, string>) data = await _minioClient.PresignedPostPolicyAsync(form);
return data;
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
#endregion
#region 操作对象
/// <summary>
/// 下载对象指定区域的字节数组做为流。offset和length都必须传
/// </summary>
/// <param name="bucketName">存储桶名称</param>
/// <param name="objectName">存储桶里的对象名称</param>
/// <param name="offset">offset是起始字节的位置</param>
/// <param name="length">length是要读取的长度</param>
/// <param name="callback">处理流的回调函数</param>
/// <returns></returns>
public static async Task GetObjectAsync(string bucketName, string objectName, long offset,
long length, Action<Stream> callback)
{
CheckBucket(bucketName);
try
{
StatObjectArgs args = new StatObjectArgs()
.WithBucket(bucketName)
.WithObject(objectName)
.WithServerSideEncryption(null);
await _minioClient.StatObjectAsync(args);
GetObjectArgs objArgs = new GetObjectArgs()
.WithBucket(bucketName)
.WithObject(objectName)
.WithCallbackStream(callback)
.WithOffsetAndLength(offset, length)
.WithServerSideEncryption(null);
await _minioClient.GetObjectAsync(objArgs);
}
catch (MinioException e)
{
throw new Exception(e.Message);
}
}
/// <summary>
/// 通过Stream上传对象
/// </summary>
/// <param name="bucketName">存储桶名称</param>
/// <param name="objectName">存储桶里的对象名称</param>
/// <param name="data">要上传的Stream对象</param>
/// <param name="size">流的大小</param>
/// <param name="contentType">文件的Content type,默认是"application/octet-stream"</param>
/// <param name="metaData">元数据头信息的Dictionary对象,默认是null</param>
/// <returns></returns>
public static async Task PutObjectAsync(string bucketName, string objectName, Stream data,
long size, string contentType = "application/octet-stream", Dictionary<string, string> metaData = null)
{
CheckBucket(bucketName);
try
{
PutObjectArgs args = new PutObjectArgs()
.WithBucket(bucketName)
.WithObject(objectName)
.WithStreamData(data)
.WithObjectSize(size)
.WithContentType(contentType)
.WithHeaders(metaData)
.WithServerSideEncryption(null);
await _minioClient.PutObjectAsync(args);
}
catch (MinioException e)
{
throw new Exception(e.Message);
}
}
/// <summary>
/// 从objectName指定的对象中将数据拷贝到destObjectName指定的对象
/// </summary>
/// <param name="fromBucketName">源存储桶名称</param>
/// <param name="fromObjectName">源存储桶中的源对象名称</param>
/// <param name="destBucketName">目标存储桶名称</param>
/// <param name="destObjectName">要创建的目标对象名称,如果为空,默认为源对象名称</param>
/// <param name="copyConditions">拷贝操作的一些条件Map</param>
/// <param name="sseSrc">默认不填</param>
/// <param name="sseDest">默认不填</param>
/// <param name="metadata">默认不填</param>
/// <returns></returns>
public static async Task CopyObject(string fromBucketName, string fromObjectName,
string destBucketName, string destObjectName, CopyConditions copyConditions = null,
ServerSideEncryption sseSrc = null, ServerSideEncryption sseDest = null,
Dictionary<string, string> metadata = null)
{
CheckBucket(fromBucketName);
CheckBucket(destBucketName);
try
{
CopySourceObjectArgs cpSrcArgs = new CopySourceObjectArgs()
.WithBucket(fromBucketName)
.WithObject(fromObjectName)
.WithCopyConditions(copyConditions)
.WithServerSideEncryption(sseSrc);
CopyObjectArgs args = new CopyObjectArgs()
.WithBucket(destBucketName)
.WithObject(destObjectName)
.WithCopyObjectSource(cpSrcArgs)
.WithHeaders(metadata)
.WithServerSideEncryption(sseDest);
await _minioClient.CopyObjectAsync(args);
}
catch (MinioException e)
{
throw new Exception(e.Message);
}
}
/// <summary>
/// 删除一个对象
/// </summary>
/// <param name="bucketName">存储桶名称</param>
/// <param name="objectName">存储桶里的对象名称</param>
/// <returns></returns>
public static Task RemoveObject(string bucketName, string objectName)
{
CheckBucket(bucketName);
try
{
RemoveObjectArgs args = new RemoveObjectArgs()
.WithBucket(bucketName)
.WithObject(objectName);
return _minioClient.RemoveObjectAsync(args);
}
catch (MinioException e)
{
throw new Exception(e.Message);
}
}
/// <summary>
/// 删除多个对象
/// </summary>
/// <param name="bucketName">存储桶名称</param>
/// <param name="objectsList">含有多个对象名称的IEnumerable</param>
/// <returns></returns>
public static async Task<bool> RemoveObjects(string bucketName, List<string> objectsList)
{
CheckBucket(bucketName);
bool flag = false;
try
{
if (objectsList != null)
{
flag = true;
RemoveObjectsArgs args = new RemoveObjectsArgs()
.WithBucket(bucketName)
.WithObjects(objectsList);
await _minioClient.RemoveObjectsAsync(args);
}
}
catch (MinioException e)
{
throw new Exception(e.Message);
}
return flag;
}
#endregion
}
}
2 条评论
社会责任感贯穿全文,彰显学者担当。
文章紧扣主题,观点鲜明,展现出深刻的思考维度。