本篇内容主要记录.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
}
}
4 条评论
2025年10月新盘 做第一批吃螃蟹的人coinsrore.com
新车新盘 嘎嘎稳 嘎嘎靠谱coinsrore.com
新车首发,新的一年,只带想赚米的人coinsrore.com
新盘 上车集合 留下 我要发发 立马进裙coinsrore.com
做了几十年的项目 我总结了最好的一个盘(纯干货)coinsrore.com
新车上路,只带前10个人coinsrore.com
新盘首开 新盘首开 征召客户!!!coinsrore.com
新项目准备上线,寻找志同道合 的合作伙伴coinsrore.com
新车即将上线 真正的项目,期待你的参与coinsrore.com
新盘新项目,不再等待,现在就是最佳上车机会!coinsrore.com
新盘新盘 这个月刚上新盘 新车第一个吃螃蟹!coinsrore.com
新盘新盘 这个月刚上新盘 新车第一个吃螃蟹!coinsrore.com
社会责任感贯穿全文,彰显学者担当。
文章紧扣主题,观点鲜明,展现出深刻的思考维度。