.netcore 对象存储帮助类
说明:
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; } } } }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤