.net 5 上传文件到阿里云的OSS 文件的上传、下载 和文件的管理
1.先购买阿里云的oss服务器
2.添加子用户 会生成 AccessKeyId 和 AccessKeySecret 记录下来
3.给当前子用户添加管理阿里云oss 的权限
//所需要用到的类
public class FileBaseRequest { /// <summary> /// 文件名称 /// </summary> public string Name { get; set; } /// <summary> /// 文件大小 /// </summary> public long? Size { get; set; } /// <summary> /// 文件宽度 /// </summary> public int? Width { get; set; } /// <summary> /// 文件高度 /// </summary> public int? Height { get; set; } /// <summary> /// 文件类型 /// </summary> public string Type { get; set; } /// <summary> /// 文件唯一的Guid /// </summary> public string Guid { get; set; } /// <summary> /// 图片形状 /// </summary> public int ShapeTypeId { get; set; } /// <summary> /// url 地址 /// </summary> public string FilebaseUrl { get; set; } /// <summary> /// hash /// </summary> public string Hash { get; set; } }
public class DownFileInfo { public string Name { get; set; } public string Url { get; set; } }
public class ReturnBox { public int Code { get; set; } = 200; public object Data { get; set; } public string Message { get; set; } = "Success"; }
//连接的Helper 在使用前 在包管理工具中安装阿里云的包 Aliyun.OSS.Core, Version=2.13.0.0 按着自己的EF 或者 Core 都行
public class OSSHelper { #region Fields //https://zww1.oss-cn-shenzhen.aliyuncs.com/xxxxxx/filebase_dev/oringinal/123456dfsf.png private static OssClient _ossClient; private static AutoResetEvent _event; //账号Id private const string AccessKeyId = "xxxxxxxxxx"; //账号key private const string AccessKeySecret = "xxxxxxxxxx"; //oss所在的服务区域 private const string Endpoint = "https://oss-cn-shenzhen.aliyuncs.com"; //生成的图片的路径地址 private const string Branch = @"xxxxxx/filebase_dev/"; // 填写Bucket名称。 private const string BucketName = "zww1"; // 填写Object完整路径。Object完整路径中不能包含Bucket名称。 private const string objectName = "/xxxxxx/filebase_dev/"; // 填写字符串。 private const string objectContent = ""; private const string ThumbSize = "350"; private const string DefaultSize = "750"; #endregion #region Constructors private OSSHelper() { _event = new AutoResetEvent(false); _ossClient = new OssClient(Endpoint, AccessKeyId, AccessKeySecret); } public static OSSHelper _() { return new OSSHelper(); } #endregion #region Method /// <summary> /// 通过文件流普通上传 10 普通上传 20 断点续传上传 30进度条上传 /// </summary> /// <returns></returns> public async Task<FileBaseRequest> HttpUpload(IFormFile file, int uploadtype = 10) { string nameStr = string.Empty; string name = file.FileName; if (!string.IsNullOrEmpty(name) && name.Contains('.')) { nameStr = name.Split('.')[0]; } string type = file.ContentType; string guid = Guid.NewGuid().ToString(); string filebaseUrl = string.Empty; string hash = ""; long? size = 0; int? width = 0; int? height = 0; int? shapeTypeId = 0; var strArr = type.Split('/'); using (var memoryStream = new MemoryStream()) { await file.CopyToAsync(memoryStream); size = file.Length; hash = ComputeMd5Hash(memoryStream); if (strArr[0].ToString() == "image") { using (Bitmap pic = new Bitmap(memoryStream)) { width = pic.Size.Width; height = pic.Size.Height; if (width > height) shapeTypeId = (int)ShapeType.Sideways; if (width < height) shapeTypeId = (int)ShapeType.vertical; if (width == height) shapeTypeId = (int)ShapeType.Square; } } if (strArr[0].ToString() == "video") { } byte[] oringinalBuffer, thumbBuffer, defaultBuffer; oringinalBuffer = memoryStream.ToArray(); thumbBuffer = GetThumbnail(oringinalBuffer, int.Parse(ThumbSize)); defaultBuffer = GetThumbnail(oringinalBuffer, int.Parse(DefaultSize)); switch (uploadtype) { case 10: using (MemoryStream requestContent = new MemoryStream(oringinalBuffer)) { filebaseUrl = $"{Branch}oringinal/{guid}.jpg"; _ossClient.PutObject(BucketName, filebaseUrl, requestContent); } using (MemoryStream requestContent = new MemoryStream(thumbBuffer)) { _ossClient.PutObject(BucketName, $"{Branch}thumb/{guid}.jpg", requestContent); } using (MemoryStream requestContent = new MemoryStream(defaultBuffer)) { _ossClient.PutObject(BucketName, $"{Branch}default/{guid}.jpg", requestContent); } break; case 20: using (MemoryStream requestContent = new MemoryStream(oringinalBuffer)) { filebaseUrl = $"{Branch}oringinal/{guid}.jpg"; var result = BreakPoint(BucketName, filebaseUrl, requestContent, nameStr); } using (MemoryStream requestContent = new MemoryStream(thumbBuffer)) { var result = BreakPoint(BucketName, $"{Branch}thumb/{guid}.jpg", requestContent, nameStr); } using (MemoryStream requestContent = new MemoryStream(defaultBuffer)) { var result = BreakPoint(BucketName, $"{Branch}default/{guid}.jpg", requestContent, nameStr); } break; case 30: using (MemoryStream requestContent = new MemoryStream(oringinalBuffer)) { filebaseUrl = $"{Branch}oringinal/{guid}.jpg"; var result = PutObjectProgress(BucketName, filebaseUrl, requestContent); } using (MemoryStream requestContent = new MemoryStream(thumbBuffer)) { var result = PutObjectProgress(BucketName, $"{Branch}thumb/{guid}.jpg", requestContent); } using (MemoryStream requestContent = new MemoryStream(defaultBuffer)) { var result = PutObjectProgress(BucketName, $"{Branch}default/{guid}.jpg", requestContent); } break; default: break; } } return new FileBaseRequest { FilebaseUrl = $"https://zww1.oss-cn-shenzhen.aliyuncs.com/{filebaseUrl}", Guid = guid, Hash = hash, Height = height, Name = name, ShapeTypeId = (int)shapeTypeId, Size = size, Type = type, Width = width, }; } /// <summary> /// 单条下载 /// </summary> /// <returns></returns> public async Task<byte[]> HttpDownload(string url) { try { RestClient restClient = new RestClient(); var request = new RestRequest(url); var byteFile = restClient.DownloadData(request); return byteFile; } catch (Exception ex) { throw new AggregateException(ex.Message); } } /// <summary> /// 单条下载文件并转流 /// </summary> /// <param name="fileName">文件路径</param> /// <param name="isDelete">是否删除临时文件</param> /// <returns></returns> public Stream FileToStream(string fileName, bool isDelete = false, string url = null) { using (var client = new WebClient()) { string tempFile = Path.GetTempFileName(); client.DownloadFile(url, tempFile);//下载临时文件 //Console.WriteLine("Using " + tempFile); //打开文件 FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); // 读取文件的 byte[] byte[] bytes = new byte[fileStream.Length]; fileStream.Read(bytes, 0, bytes.Length); fileStream.Close(); // 把 byte[] 转换成 Stream Stream stream = new MemoryStream(bytes); if (isDelete) { File.Delete(fileName);//删除临时文件 } return stream; } } /// <summary> /// 通过文件列表的Url地址下载文件 /// </summary> /// <param name="url">下载文件地址</param> /// <returns></returns> public async Task<Stream> HttpDownloadList(List<DownFileInfo> downFileInfos) { byte[] buffer = new byte[] { }; foreach (var item in downFileInfos) { RestClient restClient = new RestClient(); var request = new RestRequest(item.Url); buffer = restClient.DownloadData(request); } return new MemoryStream(buffer); } #endregion #region Utilities /// <summary> /// 进度条上传方法 /// </summary> /// <param name="BucketName"></param> /// <param name="objectName"></param> /// <param name="stream"></param> /// <param name="CheckpointDir"></param> /// <returns></returns> public async Task<bool> PutObjectProgress(string bucketName, string objectName, Stream stream) { bool state = true; try { var putObjectRequest = new PutObjectRequest(bucketName, objectName, stream); putObjectRequest.StreamTransferProgress += streamProgressCallback; _ossClient.PutObject(putObjectRequest); } catch (OssException ex) { throw new AggregateException($"Failed with error code: {ex.ErrorCode}; Error info: { ex.Message}. \nRequestID: {ex.RequestId}\tHostID: {ex.HostId}"); } catch (Exception ex) { throw new AggregateException(ex.Message); } return state; } // 获取上传进度。 private static void streamProgressCallback(object sender, StreamTransferProgressArgs args) { System.Console.WriteLine($"ProgressCallback - Progress: {args.TransferredBytes * 100 / args.TotalBytes}%, TotalBytes:{args.TotalBytes}, TransferredBytes:{args.TransferredBytes}"); } /// <summary> /// 断点续传上传方法 /// </summary> /// <param name="BucketName"></param> /// <param name="objectName"></param> /// <param name="stream"></param> /// <param name="CheckpointDir"></param> /// <returns></returns> /// <exception cref="AggregateException"></exception> public async Task<bool> BreakPoint(string BucketName, string objectName, Stream stream, string CheckpointDir) { bool back = false; try { // 通过UploadFileRequest设置多个参数。 UploadObjectRequest request = new UploadObjectRequest(BucketName, objectName, stream) { // 指定上传的分片大小。 PartSize = 8 * 1024 * 1024, // 指定并发线程数。 ParallelThreadCount = 10, // checkpointDir保存断点续传的中间状态,用于失败后继续上传。 // 如果checkpointDir为null,断点续传功能不会生效,每次失败后都会重新上传。 CheckpointDir = CheckpointDir, UploadStream = stream }; // 断点续传上传。 _ossClient.ResumableUploadObject(request); return true; } catch (OssException ex) { throw new AggregateException($"Failed with error code: {ex.ErrorCode}; Error info: {ex.Message}. \nRequestID:{ex.RequestId}\tHostID:{ex.HostId}"); } catch (Exception ex) { throw new AggregateException(ex.Message); } } /// <summary> /// 压缩图片 /// </summary> /// <param name="buffer"></param> /// <param name="targetSize">目标大小</param> /// <param name="orientation">旋转方向</param> /// <returns></returns> private Byte[] GetThumbnail(byte[] buffer, int targetSize, int orientation = 0) { using (var memoryStream = new MemoryStream(buffer)) { if (targetSize == 0) { return buffer; } using (Image image = new Bitmap(memoryStream)) { if (image.Width < targetSize) { return buffer; } //方向旋转 Rotation(image, image.Width, image.Height, 0); //计算比例 var data = CalculateDimensions(image.Size, targetSize); //开始压缩 System.Drawing.Image thumbImage = image.GetThumbnailImage(data.Width, data.Height, new Image.GetThumbnailImageAbort(ThumbnailCallback), System.IntPtr.Zero); using MemoryStream backStream = new MemoryStream(); thumbImage.Save(backStream, ImageFormat.Jpeg); //关闭缩略图对象 thumbImage.Dispose(); return backStream.GetBuffer(); } } } private bool ThumbnailCallback() { return false; } /// <summary> /// 方向选择 旋转 /// </summary> /// <param name="image"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="orientation"></param> private void Rotation(Image image, int width, int height, int orientation) { int ow = width; switch (orientation) { case 2: image.RotateFlip(RotateFlipType.RotateNoneFlipX); break; case 3: image.RotateFlip(RotateFlipType.Rotate180FlipNone); break; case 4: image.RotateFlip(RotateFlipType.RotateNoneFlipY); break; case 5: image.RotateFlip(RotateFlipType.Rotate90FlipX); break; case 6: image.RotateFlip(RotateFlipType.Rotate90FlipNone); width = height; height = ow; break; case 7: image.RotateFlip(RotateFlipType.Rotate270FlipX); break; case 8: image.RotateFlip(RotateFlipType.Rotate270FlipNone); width = height; height = ow; break; default: break; } } private Size CalculateDimensions(Size oldSize, int targetSize, bool autoResize = false) { Size newSize = new Size(); if (autoResize && oldSize.Height > oldSize.Width) { newSize.Width = (int)(oldSize.Width * ((float)targetSize / (float)oldSize.Height)); newSize.Height = targetSize; } else { newSize.Width = targetSize; newSize.Height = (int)(oldSize.Height * ((float)targetSize / (float)oldSize.Width)); } return newSize; } /// <summary> /// MD5加密 /// </summary> /// <param name="stream"></param> /// <returns></returns> private string ComputeMd5Hash(MemoryStream stream) { string hash = ""; using (MD5 md5 = MD5.Create()) { stream.Position = 0; foreach (var item in md5.ComputeHash(stream)) { hash += item.ToString("x2"); } } return hash; } /// <summary> /// 获取图片的宽高 /// </summary> /// <param name="file"></param> /// <returns></returns> public async Task<Tuple<int, int>> GetImagesInfo(IFormFile file) { int width = 0; int height = 0; using (var memoryStream = new MemoryStream()) { await file.CopyToAsync(memoryStream); using (Bitmap pic = new Bitmap(memoryStream)) { width = pic.Size.Width; height = pic.Size.Height; } } return new Tuple<int, int>(width, height); } #endregion }
//最后在Controller 中调用
[Authorize(Policy = "UniPermission")] public class FileManageController : ControllerBase { [HttpGet] [Route("/")] [AllowAnonymous] public IActionResult Get() { return Ok("this is test"); } /// <summary> /// 上传 10 普通上传 20 断点续传上传 30进度条上传 /// </summary> /// <returns></returns> [HttpPost("/upload")] public async Task<IActionResult> Upload() { try { int type = 10; var files = Request.Form.Files; if (Request.Form.ContainsKey("Type")) { string str = Request?.Form["Type"].ToString(); type = int.Parse(string.IsNullOrEmpty(str) ? "10" : str); } List<FileBaseRequest> fileBaseRequests = new List<FileBaseRequest>(); foreach (var file in files) { var result = await OSSHelper._().HttpUpload(file, type); fileBaseRequests.Add(result); } return Ok(new ReturnBox { Data = fileBaseRequests }); } catch (System.Exception ex) { return Ok(new ReturnBox { Code = 400, Message = ex.Message.ToString() }); throw; } } /// <summary> /// 批量下载 /// </summary> /// <param name="downFileInfos"></param> /// <returns></returns> [HttpPost("/downloads")] public async Task<IActionResult> Download([FromBody] List<DownFileInfo> downFileInfos) { var result = await OSSHelper._().HttpDownloadList(downFileInfos); return Ok(result); } /// <summary> /// 单条下载 /// </summary> /// <param name="url"></param> /// <returns></returns> [HttpGet("/download")] [AllowAnonymous] public async Task<IActionResult> Packing(string url)//JsonElement jsonElement { var result = await OSSHelper._().HttpDownload(url); return File(result, "image/jpeg"); } }
一切准备就绪后 使用 postman 测试
成功后返回当前图片的信息,在oss 中 生成不同类型的图片 选中图片能看到图片对应的 url
在本项目上传中使用的是简单上传
针对更多的上传方式 参考官方文档 https://www.alibabacloud.com/help/zh/doc-detail/91093.htm?spm=a2c63.p38356.b99.680.5fab7207rHS5QX
好了目前到这里就结束了 可自行扩展 仅供参考
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架