说明:
1、由于各平台对象存储规则存在细微差异,故在类中对于入参进行处理(使用时需要根据自身情况调整)。
2、本文档写于2024年05月24日,由于版本的迭代,可能存在细微差异,可能导致错误,所以推荐下载文档使用NuGet引用版本进行测试。
minio对象存储帮助类
using Minio;
using Minio.DataModel;
using Minio.Exceptions;
namespace Zowie.Common.Helper
{
/// <summary>
/// Minio
/// NuGet引用Minio.AspNetCore,版本:5.0.0
/// </summary>
public class MinioHelper
{
private MinioClient _minioClient;
public MinioHelper()
{
var apiPath = "Endpoint";//例如:192.168.1.1:9000,这里不要带http或https
var minioUser = "AccessKey";//minio账号
var minioPwd = "SecretKey";//minio密码
_minioClient = new MinioClient().WithEndpoint(apiPath).WithCredentials(minioUser, minioPwd).Build();
}
public MinioHelper(string apiPath, string minioUser, string minioPwd)
{
_minioClient = new MinioClient().WithEndpoint(apiPath).WithCredentials(minioUser, minioPwd).Build();
}
#region 操作存储桶
/// <summary>
/// 操作存储桶
/// </summary>
/// <param name="bucketName">存储桶名称</param>
/// <param name="loc">可选参数</param>
/// <returns></returns>
public async Task MakeBucket(string bucketName, string loc = "us-east-1")
{
try
{
bool found = await BucketExists(bucketName);
if (found)
{
throw new Exception(string.Format("存储桶[{0}]已存在", bucketName));
}
MakeBucketArgs args = new MakeBucketArgs()
.WithBucket(bucketName)
.WithLocation(loc);
await _minioClient.MakeBucketAsync(args);
//设置桶的访问权限(读、写、读和写)
await SetPolicyAsync(bucketName, 3);
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
/// <summary>
/// 校验是否存在,如果不存在则报错
/// </summary>
/// <param name="bucketName"></param>
private async Task CheckBucket(string bucketName)
{
bool found = await BucketExists(bucketName);
if (!found)
{
await MakeBucket(bucketName);
//throw new Exception(string.Format("存储桶[{0}]不存在", bucketName));
}
}
/// <summary>
/// 检查存储桶是否存在
/// </summary>
/// <param name="bucketName">存储桶名称</param>
/// <returns></returns>
public async Task<bool> BucketExists(string bucketName, CancellationToken cancellationToken = default(CancellationToken))
{
try
{
BucketExistsArgs args = new BucketExistsArgs()
.WithBucket(bucketName);
return await _minioClient.BucketExistsAsync(args);
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
#endregion 操作存储桶
#region 操作文件对象
/// <summary>
/// 判断桶里,对应路径文件是否存在
/// </summary>
/// <param name="bucketName">桶名</param>
/// <param name="objectName">存储桶里的对象名称,相对路径。例如/shouji/test.jpg</param>
/// <returns></returns>
public async Task<bool> FileExist(string bucketName, string objectName)
{
try
{
var obj = new StatObjectArgs().WithBucket(bucketName)
.WithObject(objectName);
await _minioClient.StatObjectAsync(obj);
}
catch (AggregateException e)
{
foreach (var item in e.InnerExceptions)
{
if (item is ObjectNotFoundException notFound)
{
return false;
}
}
}
return true;
}
/// <summary>
/// 从桶下载文件到流
/// </summary>
/// <param name="bucketName">存储桶名称</param>
/// <param name="objectName">存储桶里的对象名称,相对路径。例如/shouji/test.jpg</param>
/// <param name="sse"></param>
/// <returns></returns>
public async Task<ObjectStat> FGetObject(string bucketName, string objectName, IServerSideEncryption sse = null, Action<Stream> cb = null)
{
await CheckBucket(bucketName);
try
{
GetObjectArgs args = new GetObjectArgs()
.WithBucket(bucketName)
.WithObject(objectName)
.WithServerSideEncryption(sse)
.WithCallbackStream(cb);
return await _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 async Task FGetObject(string bucketName, string objectName, string fileName, IServerSideEncryption sse = null)
{
await CheckBucket(bucketName);
if (objectName.StartsWith('/'))
{
objectName = objectName.Substring(1);
}
fileName = fileName.Replace("\\", "/").Replace("//", "/");
// 确保本地目录结构存在
string path = Path.GetDirectoryName(fileName);
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
if (File.Exists(fileName))
{
File.Delete(fileName);
}
GetObjectArgs args = new GetObjectArgs()
.WithBucket(bucketName)
.WithObject(objectName)//上传到minio服务器中生成的objectName
.WithFile(fileName);// D:\\photo.jpg
await _minioClient.GetObjectAsync(args);
}
/// <summary>
/// 根据本地相对路径上传到服务器对应的相对路径
/// </summary>
/// <param name="file">绝对路径。例如D:/Project/shouji/test.jpg</param>
/// <param name="filePath">存储桶里的对象名称,相对路径。例如/shouji/test.jpg</param>
/// <returns></returns>
public async Task<bool> UploadFileForBendi(string bucketName, string file, string filePath, string contentType = "application/octet-stream")
{
string toPath = filePath.Replace($"/{bucketName}/", "").Replace($"{bucketName}/", "");
//上传到MinIO中的文件名称
string[] leftSplit = file.Split('/');
string[] rightSplit = leftSplit[leftSplit.Length - 1].Split('\\');
string objName = rightSplit[rightSplit.Length - 1];
if (!string.IsNullOrEmpty(toPath))
{
if (toPath.Contains(objName))
{
toPath = toPath.Replace(objName, "");
}
else if (toPath.Substring(toPath.Length - 1, 1) != "/")
{
toPath += "/";
}
}
objName = toPath + objName;
bool result = await Task.Run(async () =>
{
try
{
await CheckBucket(bucketName);
if (objName.ToLower().EndsWith(".png"))
{
contentType = "image/png";
}
else if (objName.ToLower().EndsWith(".jpg") || objName.ToLower().EndsWith(".jpeg"))
{
contentType = "image/jpeg";
}
else if (objName.ToLower().EndsWith(".gif"))
{
contentType = "image/gif";
}
else if (objName.ToLower().EndsWith(".mp4"))
{
contentType = "video/mp4";
}
byte[] bs = File.ReadAllBytes(file);
System.IO.MemoryStream filestream = new System.IO.MemoryStream(bs);
PutObjectArgs args = new PutObjectArgs()
.WithBucket(bucketName)
.WithObject("/" + objName)
.WithStreamData(filestream)
.WithContentType(contentType)
.WithObjectSize(filestream.Length);
var ret = await _minioClient.PutObjectAsync(args);
filestream.Close();
return true;
}
catch (MinioException e)
{
throw e;
}
});
return result;
}
/// <summary>
/// 上传本地文件至存储桶
/// </summary>
/// <param name="bucketName">存储桶名称</param>
/// <param name="objectName">存储桶里的对象名称,相对路径。例如/shouji/test.jpg</param>
/// <returns></returns>
public async Task FPutObject(string bucketName, string objectName, Stream stream, string contentType = "application/octet-stream", Dictionary<string, string> metaData = null, IServerSideEncryption sse = null)
{
await CheckBucket(bucketName);
try
{
//var data= _minioClient.PutObjectAsync(bucketName, objectName, fileName, contentType: "application/octet-stream");
PutObjectArgs args = new PutObjectArgs()
.WithBucket(bucketName)
.WithObject(objectName)
.WithStreamData(stream)
.WithContentType(contentType)
.WithHeaders(metaData)
.WithObjectSize(stream.Length)
.WithServerSideEncryption(sse);
var ret = await _minioClient.PutObjectAsync(args);
}
catch (MinioException e)
{
throw new Exception(e.Message);
}
}
#endregion 操作文件对象
#region 操作对象
/// <summary>删除一个对象
/// 删除一个对象
/// </summary>
/// <param name="minio">连接实例</param>
/// <param name="bucketName">存储桶名称</param>
/// <param name="objectName">存储桶里的对象名称</param>
/// <returns></returns>
public async Task RemoveObject(string bucketName, string objectName)
{
await CheckBucket(bucketName);
try
{
RemoveObjectArgs args = new RemoveObjectArgs()
.WithBucket(bucketName)
.WithObject(objectName);
await _minioClient.RemoveObjectAsync(args);
}
catch (MinioException e)
{
throw new Exception(e.Message);
}
}
/// <summary>删除多个对象
/// 删除多个对象
/// </summary>
/// <param name="minio">连接实例</param>
/// <param name="bucketName">存储桶名称</param>
/// <param name="objectsList">含有多个对象名称的IEnumerable</param>
/// <returns></returns>
public async Task<bool> RemoveObjects(string bucketName, List<string> objectsList)
{
await CheckBucket(bucketName);
bool flag = false;
try
{
if (objectsList != null)
{
//IObservable<DeleteError> objectsOservable = await _minioClient.RemoveObjectAsync(bucketName, objectsList).ConfigureAwait(false);
flag = true;
//IDisposable objectsSubscription = objectsOservable.Subscribe(
// objDeleteError => Console.WriteLine($"Object: {objDeleteError.Key}"),
// ex => Console.WriteLine($"OnError: {ex}"),
// () =>
// {
// Console.WriteLine($"Removed objects in list from {bucketName}\n");
// });
//return;
RemoveObjectsArgs args = new RemoveObjectsArgs()
.WithBucket(bucketName)
.WithObjects(objectsList);
await _minioClient.RemoveObjectsAsync(args);
}
}
catch (MinioException e)
{
throw new Exception(e.Message);
}
return flag;
}
private async Task SetPolicyAsync(string bucketName, int policyType = 1)
{
//设置桶的访问权限(读、写、读和写)
var policyRead = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\"],\"Resource\":[\"arn:aws:s3:::BUCKETNAME\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:ListBucket\"],\"Resource\":[\"arn:aws:s3:::BUCKETNAME\"],\"Condition\":{\"StringEquals\":{\"s3:prefix\":[\"BUCKETPREFIX\"]}}},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetObject\"],\"Resource\":[\"arn:aws:s3:::BUCKETNAME/BUCKETPREFIX*\"]}]}";
var policyWrite = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucketMultipartUploads\"],\"Resource\":[\"arn:aws:s3:::BUCKETNAME\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:AbortMultipartUpload\",\"s3:DeleteObject\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\"],\"Resource\":[\"arn:aws:s3:::BUCKETNAME/BUCKETPREFIX*\"]}]}";
var policyReadWrite = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucketMultipartUploads\"],\"Resource\":[\"arn:aws:s3:::BUCKETNAME\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:ListBucket\"],\"Resource\":[\"arn:aws:s3:::BUCKETNAME\"],\"Condition\":{\"StringEquals\":{\"s3:prefix\":[\"BUCKETPREFIX\"]}}},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:PutObject\",\"s3:AbortMultipartUpload\",\"s3:DeleteObject\",\"s3:GetObject\",\"s3:ListMultipartUploadParts\"],\"Resource\":[\"arn:aws:s3:::BUCKETNAME/BUCKETPREFIX*\"]}]}";
var policySet = policyType == 1 ? policyRead : policyType == 2 ? policyWrite : policyReadWrite;
SetPolicyArgs policyArgs = new SetPolicyArgs()
.WithBucket(bucketName)
.WithPolicy(policySet.Replace("BUCKETNAME", bucketName).Replace("BUCKETPREFIX", "*.*"));
await _minioClient.SetPolicyAsync(policyArgs);
}
#endregion 操作对象
/// <summary>生成一个给HTTP GET请求用的presigned URL。浏览器/移动端的客户端可以用这个URL进行下载,即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间,默认值是7天。
/// 生成一个给HTTP GET请求用的presigned URL。浏览器/移动端的客户端可以用这个URL进行下载,即使其所在的存储桶是私有的。这个presigned URL可以设置一个失效时间,默认值是7天。
/// </summary>
/// <param name="minio">连接实例</param>
/// <param name="bucketName">存储桶名称</param>
/// <param name="objectName">存储桶里的对象名称</param>
/// <param name="expiresInt">失效时间(以秒为单位),默认是7天,不得大于七天</param>
/// <param name="reqParams">额外的响应头信息,支持response-expires、response-content-type、response-cache-control、response-content-disposition</param>
/// <returns></returns>
public async Task<string> PresignedGetObject(string bucketName, string objectName, int expiresInt = 1000)
{
try
{
PresignedGetObjectArgs args = new PresignedGetObjectArgs()
.WithBucket(bucketName)
.WithObject(objectName)
.WithExpiry(expiresInt);
return await _minioClient.PresignedGetObjectAsync(args);
}
catch (Exception e)
{
return null;
}
}
}
}
阿里云对象存储帮助类
using Aliyun.OSS;
using System.Text.RegularExpressions;
namespace Zowie.Common.Helper
{
/// <summary>
/// 阿里云OSS
/// NuGet引用Aliyun.OSS.SDK.NetCore,版本:2.13.0
/// </summary>
public class ALiYunHelper
{
private OssClient client;
public ALiYunHelper()
{
var endpoint = "Endpoint";
var accessKey = "AccessKey";
var secretKey = "SecretKey";
client = new OssClient(endpoint, accessKey, secretKey);
}
// 创建一个存储桶
public string CreateBucket(string? bucketName = null)
{
try
{
// 创建存储空间。
var bucket = client.CreateBucket(bucketName);
// 设置存储空间的读写权限为公共读。
client.SetBucketAcl(bucketName, CannedAccessControlList.PublicRead);
return ("Create bucket succeeded, " + bucket.Name);
}
catch (Exception ex)
{
return ("Create bucket failed, " + ex.Message);
}
}
/// <summary>
/// 判断存储空间是否存在,不存在就创建,存在bug,未找到判断存储桶是否存在逻辑,这里如果目录里包含也会返回true
/// </summary>
/// <param name="bucketName">桶名</param>
public void DoesBucketExist(string bucketName)
{
try
{
var exist = client.DoesBucketExist(bucketName);
if (!exist)
{
CreateBucket(bucketName);
}
}
catch (Exception ex)
{
return;
}
}
/// <summary>
/// 上传
/// </summary>
/// <param name="bucketName">填写Bucket名称,例如examplebucket</param>
/// <param name="objectName">相对路径,相对路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。</param>
/// <param name="localFilename">绝对路径,例如D:\\localpath\\examplefile.txt</param>
/// <returns></returns>
public bool UploadFile(string bucketName, string objectName, string localFilename)
{
//objectName = "shouji/chongqing/rongchang/2023/10/17/202310171501034B62CC.jpg";
// 填写本地文件完整路径,例如D:\\localpath\\examplefile.txt。如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。
//localFilename = "C:/Users/Zowie/Desktop/1.png";
try
{
if (objectName.StartsWith('/'))
{
objectName = objectName.Substring(1);
}
string pattern = @"\\|/";
string replacement = @"/";
Regex rgx = new Regex(pattern);
localFilename = rgx.Replace(localFilename, replacement);
// 上传文件。
var result = client.PutObject(bucketName, objectName, localFilename);
return true;
}
catch (Exception ex)
{
return false;
}
}
/// <summary>
/// 存储一个字符串
/// </summary>
/// <param name="bucketName">存储空间名称</param>
/// <param name="objectName">相对路径,相对路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。</param>
/// <param name="stream">字符内容</param>
/// <returns></returns>
public bool PutString(string bucketName, string objectName, Stream stream)
{
try
{
if (objectName.StartsWith('/'))
{
objectName = objectName.Substring(1);
}
// 上传文件。
client.PutObject(bucketName, objectName, stream);
}
catch (Exception ex)
{
return false;
}
return true;
}
/// <summary>
/// 上传文件
/// </summary>
/// <param name="bucketName">存储空间名称</param>
/// <param name="fileToUpload">文件路径。例如D:\\localpath\\examplefile.txt</param>
/// <param name="objectName">相对路径,相对路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。</param>
/// <returns></returns>
public bool PutObject(string bucketName, string fileToUpload, string objectName = "")
{
if (string.IsNullOrEmpty(objectName))
{
objectName = Path.GetFileName(fileToUpload);
}
try
{
// 上传文件。
var result = client.PutObject(bucketName, objectName, fileToUpload);
}
catch (Exception ex)
{
return false;
}
return true;
}
/// <summary>
/// 删除文件
/// </summary>
/// <param name="bucketName">桶名</param>
/// <param name="objectName">相对路径,相对路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。</param>
/// <returns></returns>
public bool DeleteObject(string bucketName, string objectName)
{
try
{
if (objectName.StartsWith('/'))
{
objectName = objectName.Substring(1);
}
// 删除文件。
client.DeleteObject(bucketName, objectName);
}
catch (Exception ex)
{
return false;
}
return true;
}
/// <summary>
/// 批量删除文件
/// </summary>
/// <param name="bucketName">桶名</param>
/// <param name="objectNames">相对路径,相对路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。</param>
/// <returns></returns>
public bool DeleteObjects(string bucketName, List<string> objectNames)
{
try
{
var quietMode = true;
var request = new DeleteObjectsRequest(bucketName, objectNames, quietMode);
// 删除多个文件。
var result = client.DeleteObjects(request);
}
catch (Exception ex)
{
return false;
}
return true;
}
/// <summary>
/// 获取文件列表
/// </summary>
/// <param name="bucketName">桶名</param>
/// <returns></returns>
public List<OssObjectSummary> ListObjects(string bucketName)
{
var objectsList = new List<OssObjectSummary>();
try
{
ObjectListing result = null;
string nextMarker = string.Empty;
do
{
var listObjectsRequest = new ListObjectsRequest(bucketName)
{
Marker = nextMarker,
};
// 列举文件。
result = client.ListObjects(listObjectsRequest);
foreach (var summary in result.ObjectSummaries)
{
objectsList.Add(summary);
}
nextMarker = result.NextMarker;
} while (result.IsTruncated);
}
catch (Exception ex)
{
}
return objectsList;
}
/// <summary>
/// 把指定的OSS文件下载到流
/// </summary>
/// <param name="bucketName">桶名</param>
/// <param name="objectName">相对路径,相对路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。</param>
/// <param name="downloadFilename">填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt</param>
/// <returns></returns>
public void GetObject(string bucketName, string objectName, string downloadFilename)
{
try
{
if (objectName.StartsWith('/'))
{
objectName = objectName.Substring(1);
}
string pattern = @"\\|/";
string replacement = @"/";
Regex rgx = new Regex(pattern);
downloadFilename = rgx.Replace(downloadFilename, replacement);
// 下载文件到流。OssObject包含了文件的各种信息,如文件所在的存储空间、文件名、元信息以及一个输入流。
var obj = client.GetObject(bucketName, objectName);
using (var requestStream = obj.Content)
{
byte[] buf = new byte[1024];
var fs = System.IO.File.Open(downloadFilename, FileMode.OpenOrCreate);
var len = 0;
// 通过输入流将文件的内容读取到文件或者内存中。
while ((len = requestStream.Read(buf, 0, 1024)) != 0)
{
fs.Write(buf, 0, len);
}
fs.Close();
}
}
catch (Exception ex)
{
}
}
/// <summary>
/// 把指定的OSS文件下载到流
/// </summary>
/// <param name="bucketName">桶名</param>
/// <param name="objectName">相对路径,相对路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。</param>
/// <param name="downloadFilename">填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt</param>
/// <returns></returns>
public MemoryStream GetObject(string bucketName, string objectName)
{
try
{
if (objectName.StartsWith('/'))
{
objectName = objectName.Substring(1);
}
// 下载文件到流。OssObject包含了文件的各种信息,如文件所在的存储空间、文件名、元信息以及一个输入流。
var obj = client.GetObject(bucketName, objectName);
MemoryStream imageStream = new MemoryStream(obj.ResponseStream.ReadByte());
return imageStream;
}
catch (Exception ex)
{
return null;
}
}
/// <summary>
/// 产生带有签名的URI
/// </summary>
/// <param name="bucketName">桶名</param>
/// <param name="objectName">相对路径,相对路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。</param>
public void GenerateIamgeUri(string bucketName, string objectName)
{
try
{
var process = "image/resize,m_fixed,w_100,h_100";
var req = new GeneratePresignedUriRequest(bucketName, objectName, SignHttpMethod.Get)
{
Expiration = DateTime.Now.AddHours(1),
Process = process
};
// 产生带有签名的URI
var uri = client.GeneratePresignedUri(req);
}
catch (Exception ex)
{
}
}
/// <summary>
/// 判断文件是否存在
/// </summary>
/// <param name="bucketName"></param>
/// <param name="objectName"></param>
/// <returns></returns>
public bool DoesObjectExist(string bucketName, string objectName)
{
try
{
// 判断文件是否存在。
var exist = client.DoesObjectExist(bucketName, objectName);
return true;
}
catch (Exception ex)
{
return false;
}
}
/// <summary>
/// 断点续传下载
/// </summary>
/// <param name="bucketName"></param>
/// <param name="objectName"></param>
/// <param name="fileName"></param>
/// <returns></returns>
public bool ResumableDownloadObject(string bucketName, string objectName, string fileName)
{
try
{
// 设置断点记录文件的完整路径,例如D:\\localpath\\examplefile.txt.dcp。
// 只有当Object下载中断产生了断点记录文件后,如果需要继续下载该Object,才需要设置对应的断点记录文件。下载完成后,该文件会被删除。
var checkpointDir = "D:\\localpath\\examplefile.txt.dcp";
// 通过DownloadObjectRequest设置多个参数。
DownloadObjectRequest request = new DownloadObjectRequest(bucketName, objectName, fileName)
{
// 指定下载的分片大小,单位为字节。
PartSize = 8 * 1024 * 1024,
// 指定并发线程数。
ParallelThreadCount = 3,
// checkpointDir用于保存断点续传进度信息。如果某一分片下载失败,再次下载时会根据文件中记录的点继续下载。如果checkpointDir为null,断点续传功能不会生效,每次失败后都会重新下载。
CheckpointDir = checkpointDir,
};
// 断点续传下载。
client.ResumableDownloadObject(request);
return true;
}
catch (Exception ex)
{
return false;
}
}
}
}
天翼云对象存储帮助类
using Amazon.S3;
using Amazon.S3.Model;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text.RegularExpressions;
namespace Zowie.Common.Helper
{
/// <summary>
/// 天翼云OSS
/// NuGet引用AWSSDK.Core版本:3.7.304.3,AWSSDK.S3版本3.7.308.2
/// </summary>
public class TYiYunHelper
{
private AmazonS3Client client;
public TYiYunHelper()
{
var accessKey = "AccessKey";
var secretKey = "SecretKey";
System.Net.ServicePointManager.ServerCertificateValidationCallback +=
delegate (
object sender,
System.Security.Cryptography.X509Certificates.X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors) // 自签名忽略认证
{
return true;
};
AmazonS3Config config = new AmazonS3Config();
config.ServiceURL = "Endpoint"; // 指定IP和Port
config.ForcePathStyle = true; // 使用路径模式
config.SignatureVersion = "2"; // 签名版本
client = new AmazonS3Client(accessKey, secretKey, config); // 建立连接
}
// 创建一个存储桶
public async Task CreateBucket(string? bucketName = null)
{
try
{
if (string.IsNullOrEmpty(bucketName)) return;
PutBucketRequest request = new PutBucketRequest();
// 创建存储空间。
request.BucketName = bucketName;
// 设置存储空间的读写权限为公共读。
request.CannedACL = S3CannedACL.PublicRead;
PutBucketResponse response = await client.PutBucketAsync(request);
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 上传
/// </summary>
/// <param name="bucketName">填写Bucket名称,例如examplebucket</param>
/// <param name="key">相对路径,相对路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。</param>
/// <param name="filepath">绝对路径,例如D:\\localpath\\examplefile.txt</param>
/// <returns></returns>
public async Task<bool> UploadFile(string bucketName, string key, string filepath)
{
try
{
if (key.StartsWith('/'))
{
key = key.Substring(1);
}
string pattern = @"\\|/";
string replacement = @"/";
Regex rgx = new Regex(pattern);
filepath = rgx.Replace(filepath, replacement);
key = rgx.Replace(key, replacement);
// 上传文件。
var request = new PutObjectRequest();
request.BucketName = bucketName;
request.Key = key;
request.CannedACL = S3CannedACL.PublicRead;
request.FilePath = filepath;
if (key.ToLower().EndsWith(".png"))
{
request.ContentType = "image/png";
}
else if (key.ToLower().EndsWith(".jpg") || key.ToLower().EndsWith(".jpeg"))
{
request.ContentType = "image/jpeg";
}
else if (key.ToLower().EndsWith(".gif"))
{
request.ContentType = "image/gif";
}
else if (key.ToLower().EndsWith(".mp4"))
{
request.ContentType = "video/mp4";
}
var result = await client.PutObjectAsync(request);
return true;
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 存储一个字符串
/// </summary>
/// <param name="bucketName">填写Bucket名称,例如examplebucket</param>
/// <param name="key">相对路径,相对路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。</param>
/// <param name="inputStream">字符内容</param>
/// <returns></returns>
public async Task<bool> PutString(string bucketName, string key, Stream inputStream)
{
try
{
if (key.StartsWith('/'))
{
key = key.Substring(1);
}
string pattern = @"\\|/";
string replacement = @"/";
Regex rgx = new Regex(pattern);
// 上传文件。
var request = new PutObjectRequest();
request.BucketName = bucketName;
request.Key = key;
request.CannedACL = S3CannedACL.PublicRead;
request.InputStream = inputStream;
if (key.ToLower().EndsWith(".png"))
{
request.ContentType = "image/png";
}
else if (key.ToLower().EndsWith(".jpg") || key.ToLower().EndsWith(".jpeg"))
{
request.ContentType = "image/jpeg";
}
else if (key.ToLower().EndsWith(".gif"))
{
request.ContentType = "image/gif";
}
else if (key.ToLower().EndsWith(".mp4"))
{
request.ContentType = "video/mp4";
}
var result = await client.PutObjectAsync(request);
return true;
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 删除文件
/// </summary>
/// <param name="bucketName">桶名</param>
/// <param name="key">相对路径,相对路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。</param>
/// <returns></returns>
public async Task<bool> DeleteObject(string bucketName, string key)
{
try
{
// 删除文件。
var request = new DeleteObjectRequest();
if (key.StartsWith('/'))
{
key = key.Substring(1);
}
request.BucketName = bucketName;
request.Key = key;
request.BypassGovernanceRetention = true;
DeleteObjectResponse response = await client.DeleteObjectAsync(request);
}
catch (Exception ex)
{
throw ex;
}
return true;
}
/// <summary>
/// 批量删除文件
/// </summary>
/// <param name="bucketName">桶名</param>
/// <param name="objectNames">相对路径,相对路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。</param>
/// <returns></returns>
public async Task<bool> DeleteObjects(string bucketName, List<string> objectNames)
{
try
{
var request = new DeleteObjectsRequest();
request.BucketName = bucketName;
request.Quiet = false;
foreach (var item in objectNames)
{
request.AddKey(item);
}
request.BypassGovernanceRetention = true;
DeleteObjectsResponse response = await client.DeleteObjectsAsync(request);
}
catch (Exception ex)
{
throw ex;
}
return true;
}
/// <summary>
/// 下载文件
/// </summary>
/// <param name="bucketName">桶名</param>
/// <param name="key">相对路径,相对路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。</param>
/// <param name="filepath">填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt</param>
/// <returns></returns>
public async Task GetObject(string bucketName, string key, string filepath)
{
try
{
if (key.StartsWith('/'))
{
key = key.Substring(1);
}
string pattern = @"\\|/";
string replacement = @"/";
Regex rgx = new Regex(pattern);
filepath = rgx.Replace(filepath, replacement);
// 下载文件到流。OssObject包含了文件的各种信息,如文件所在的存储空间、文件名、元信息以及一个输入流。
var obj = await client.GetObjectAsync(bucketName, key);
using (Stream requestStream = obj.ResponseStream)
{
byte[] buf = new byte[1024];
// 确保本地目录结构存在
string path = Path.GetDirectoryName(filepath);
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
var fs = System.IO.File.Open(filepath, FileMode.OpenOrCreate);
var len = 0;
// 通过输入流将文件的内容读取到文件或者内存中。
while ((len = requestStream.Read(buf, 0, 1024)) != 0)
{
fs.Write(buf, 0, len);
}
fs.Close();
}
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 文件是否存在
/// </summary>
/// <param name="bucketName"></param>
/// <param name="key"></param>
/// <returns></returns>
public async Task<bool> FileExist(string bucketName, string key)
{
try
{
if (key.StartsWith('/'))
{
key = key.Substring(1);
}
var obj = await client.GetObjectAsync(bucketName, key);
return true;
}
catch (Exception ex)
{
throw ex;
}
}
}
}
华为云对象存储帮助类
using OBS;
using OBS.Model;
using System.Text.RegularExpressions;
namespace Zowie.Common.Helper
{
/// <summary>
/// 华为云OBS
/// NuGet引用esdk_obs_.net_core,版本:3.0.4
/// </summary>
public class HuaWeiOBSHelper
{
private ObsClient client;
public HuaWeiOBSHelper()
{
ObsConfig config = new ObsConfig();
config.Endpoint = "Endpoint";
var accessKey = "AccessKey";
var secretKey = "SecretKey";
client = new ObsClient(accessKey, secretKey, config);
}
// 创建一个存储桶
public string CreateBucket(string bucketName = null)
{
try
{
CreateBucketRequest request = new CreateBucketRequest()
{
BucketName = bucketName,
CannedAcl = CannedAclEnum.PublicRead,
};
// 创建存储空间。
var bucket = client.CreateBucket(request);
return "Create bucket succeeded";
}
catch (Exception ex)
{
return "Create bucket failed, " + ex.Message;
}
}
/// <summary>
/// 上传
/// </summary>
/// <param name="bucketName">填写Bucket名称,例如examplebucket</param>
/// <param name="objectName">相对路径,相对路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。</param>
/// <param name="localFilename">绝对路径,例如D:\\localpath\\examplefile.txt</param>
/// <returns></returns>
public bool UploadFile(string bucketName, string objectName, string localFilename)
{
try
{
if (objectName.StartsWith("/"))
{
objectName = objectName.Substring(1);
}
string pattern = @"\\|/";
string replacement = @"/";
Regex rgx = new Regex(pattern);
localFilename = rgx.Replace(localFilename, replacement);
objectName = rgx.Replace(objectName, replacement);
// 上传文件。
var request = new PutObjectRequest()
{
BucketName = bucketName,
ObjectKey = objectName,
CannedAcl = CannedAclEnum.PublicRead,
FilePath = localFilename
};
if (objectName.ToLower().EndsWith(".png"))
{
request.ContentType = "image/png";
}
else if (objectName.ToLower().EndsWith(".jpg") || objectName.ToLower().EndsWith(".jpeg"))
{
request.ContentType = "image/jpeg";
}
else if (objectName.ToLower().EndsWith(".gif"))
{
request.ContentType = "image/gif";
}
else if (objectName.ToLower().EndsWith(".mp4"))
{
request.ContentType = "video/mp4";
}
var result = client.PutObject(request);
return true;
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 存储一个字符串
/// </summary>
/// <param name="bucketName">填写Bucket名称,例如examplebucket</param>
/// <param name="objectName">相对路径,相对路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。</param>
/// <param name="inputStream">字符内容</param>
/// <returns></returns>
public bool PutString(string bucketName, string objectName, Stream inputStream)
{
try
{
if (objectName.StartsWith("/"))
{
objectName = objectName.Substring(1);
}
string pattern = @"\\|/";
string replacement = @"/";
Regex rgx = new Regex(pattern);
// 上传文件。
var request = new PutObjectRequest()
{
BucketName = bucketName,
ObjectKey = objectName,
CannedAcl = CannedAclEnum.PublicRead,
InputStream = inputStream
};
if (objectName.ToLower().EndsWith(".png"))
{
request.ContentType = "image/png";
}
else if (objectName.ToLower().EndsWith(".jpg") || objectName.ToLower().EndsWith(".jpeg"))
{
request.ContentType = "image/jpeg";
}
else if (objectName.ToLower().EndsWith(".gif"))
{
request.ContentType = "image/gif";
}
else if (objectName.ToLower().EndsWith(".mp4"))
{
request.ContentType = "video/mp4";
}
var result = client.PutObject(request);
return true;
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 删除文件
/// </summary>
/// <param name="bucketName">桶名</param>
/// <param name="objectName">相对路径,相对路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。</param>
/// <returns></returns>
public bool DeleteObject(string bucketName, string objectName)
{
try
{
if (objectName.StartsWith("/"))
{
objectName = objectName.Substring(1);
}
// 删除文件。
var request = new DeleteObjectRequest()
{
BucketName = bucketName,
ObjectKey = objectName,
};
var response = client.DeleteObject(request);
}
catch (Exception ex)
{
throw ex;
}
return true;
}
/// <summary>
/// 批量删除文件
/// </summary>
/// <param name="bucketName">桶名</param>
/// <param name="objectNames">相对路径,相对路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。</param>
/// <returns></returns>
public bool DeleteObjects(string bucketName, List<string> objectNames)
{
try
{
var request = new DeleteObjectsRequest();
request.BucketName = bucketName;
request.Quiet = false;
foreach (var item in objectNames)
{
if (item.StartsWith("/"))
request.AddKey(item.Substring(1));
else
request.AddKey(item);
}
var response = client.DeleteObjects(request);
}
catch (Exception ex)
{
throw ex;
}
return true;
}
/// <summary>
/// 下载文件
/// </summary>
/// <param name="bucketName">桶名</param>
/// <param name="objectName">相对路径,相对路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。</param>
/// <param name="filepath">填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt</param>
/// <returns></returns>
public void GetObject(string bucketName, string objectName, string filepath)
{
try
{
if (objectName.StartsWith("/"))
{
objectName = objectName.Substring(1);
}
string pattern = @"\\|/";
string replacement = @"/";
Regex rgx = new Regex(pattern);
filepath = rgx.Replace(filepath, replacement);
// 下载文件到流。OssObject包含了文件的各种信息,如文件所在的存储空间、文件名、元信息以及一个输入流。
var request = new GetObjectRequest()
{
BucketName = bucketName,
ObjectKey = objectName,
};
var obj = client.GetObject(request);
using (Stream requestStream = obj.OutputStream)
{
byte[] buf = new byte[1024];
// 确保本地目录结构存在
string path = Path.GetDirectoryName(filepath);
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
var fs = File.Open(filepath, FileMode.OpenOrCreate);
var len = 0;
// 通过输入流将文件的内容读取到文件或者内存中。
while ((len = requestStream.Read(buf, 0, 1024)) != 0)
{
fs.Write(buf, 0, len);
}
fs.Close();
}
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// 文件是否存在
/// </summary>
/// <param name="bucketName"></param>
/// <param name="objectName"></param>
/// <returns></returns>
public bool FileExist(string bucketName, string objectName)
{
try
{
if (objectName.StartsWith("/"))
{
objectName = objectName.Substring(1);
}
var request = new GetObjectRequest()
{
BucketName = bucketName,
ObjectKey = objectName,
};
var obj = client.GetObject(request);
return true;
}
catch (Exception ex)
{
throw ex;
}
}
}
}