【.net core使用minio大文件分片上传】.net core使用minio大文件分片上传以及断点续传、秒传思路

版本:.net core 7
需求:net限制了上传的大小,只能上传25M上下的文件,如果上传一个八十多兆的文件,swagger接口报错,如果前端调用上传接口,会报CORS跨域错误,这篇文章介绍怎么使用分片的方式上传到minio后合并。

1.安装AWSSDK.S3的SDK

miniio 的分片上传封装,采用了AWSSDK.S3的SDK,该SDK是兼容了亚马逊s3的接口api,而minio是采用亚马逊s3的api模式
在这里插入图片描述

2.带上我写的后端MinioHelper.cs文件的封装方法

在这里插入图片描述

ConfigConstant.MinioBucketName是minio的存储桶名称,这里示例值是micro-element
ConfigConstant.MinioUserName是minio的AccessKey,值以你自己minio服务器的AccessKey为准
ConfigConstant.MinioPassWord是minio的SecretKey,值以你自己minio服务器的SecretKey为准
ConfigConstant.MinioAddressIp是minio的地址,需要带http://ip:port,比如http://192.168.110.11/

/// <summary>
/// miniio 的分片上传封装,采用了AWSSDK.S3的SDK,该SDK是兼容了亚马逊s3的接口api,而minio是采用亚马逊s3的api模式
/// </summary>
public class MinioHelper
{private  AmazonS3Client amazonS3Client;public MinioHelper(){AmazonS3Config config = new AmazonS3Config(){ServiceURL = ConfigConstant.MinioAddressIp  //地址采用服务器minio的http://ip:port};amazonS3Client = new AmazonS3Client(ConfigConstant.MinioUserName, ConfigConstant.MinioPassWord, config);//minio的账号密码}/// <summary>/// 初始化文件获取uploadid/// </summary>/// <param name="BucketName">桶名称</param>/// <param name="KeyName">存储文件的桶路径</param>/// <returns>返回uploadID</returns>public async   Task<string> InitMultipartChunkUploadFile(string BucketName,string KeyName) {InitiateMultipartUploadRequest initRequest=  new InitiateMultipartUploadRequest{BucketName = BucketName,Key = KeyName,};InitiateMultipartUploadResponse initResponse = await amazonS3Client.InitiateMultipartUploadAsync(initRequest);return  initResponse.UploadId;}/// <summary>/// 上传分片,这是看minio web控制台是看不出来分片文件的,需要去minio存储文件夹下的.minio.sys/multipart查看/// </summary>/// <param name="BucketName">桶名称</param>/// <param name="KeyName">存储文件的桶路径</param>/// <param name="UploadId">uploadID</param>/// <param name="ChunkCount">当前第几片</param>/// <param name="PartSize">当前分片大小</param>/// <param name="ChunkFile">分片文件</param>/// <returns>返回etag和当前第几片</returns>public async  Task<PartETag> ChunkUploadAsync(string BucketName, string KeyName,string UploadId, int ChunkCount, long PartSize, Stream ChunkFile) {UploadPartRequest uploadRequest = new UploadPartRequest();uploadRequest.BucketName = BucketName;uploadRequest.Key = KeyName;uploadRequest.UploadId = UploadId;uploadRequest.PartNumber = ChunkCount;uploadRequest.InputStream = ChunkFile;uploadRequest.PartSize = PartSize;//进行分片上传UploadPartResponse up1Response = await amazonS3Client.UploadPartAsync(uploadRequest);return  new PartETag { ETag = up1Response.ETag, PartNumber = ChunkCount };}/// <summary>/// 合并分片为整个文件,合并后minio存储的文件夹里.minio.sys/multipart下该文件会删除/// </summary>/// <param name="BucketName">桶名称</param>/// <param name="KeyName">存储文件的桶路径</param>/// <param name="UploadId">uploadID</param>/// <param name="partETags">当前第几片</param>/// <returns>返回存储的Key属性字段的相对路径(location是绝对路径,该属性不可取,如果服务器迁移会使人崩溃!)</returns>public async  Task<CompleteMultipartUploadResponse> CompleteMultipartUploadFile(string BucketName, string KeyName, string UploadId, List<PartETag> partETags) {CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest{BucketName = BucketName,Key = KeyName,UploadId = UploadId,PartETags = partETags,};CompleteMultipartUploadResponse compResponse = await amazonS3Client.CompleteMultipartUploadAsync(compRequest);return compResponse;}/// <summary>/// 查询该uploadID已上传了几个分片详细信息/// </summary>/// <param name="BucketName">桶名称</param>/// <param name="KeyName">存储文件的桶路径</param>/// <param name="UploadId">uploadID</param>/// <returns>只需要返回值数组下每个对象里的eTag和partNumber</returns>public async  Task<List<PartDetail>> ListPartsUploadInfo(string BucketName, string KeyName, string UploadId) {ListPartsRequest listPartRequest = new ListPartsRequest{BucketName = BucketName,Key = KeyName,UploadId = UploadId};ListPartsResponse listPartResponse = await amazonS3Client.ListPartsAsync(listPartRequest);return listPartResponse.Parts;}
}

3.在需要使用的地方引入该项目

在这里插入图片描述

4.申明MinioHelper文件的构造函数

在这里插入图片描述

        private MinioHelper minioHelper;/// <summary>/// /// </summary>public minioUploadController(){minioHelper = new MinioHelper();}

5.初始化以及上传分片接口

 /// <summary>/// 查询上传分片列表/// </summary>/// <param name="files"></param>/// <returns></returns>[HttpPost("/file/ListPartsFile")]public async Task<dynamic> ListPartsFile(string Name, string UploadId = ""){List<PartDetail> listPartResponse =new List<PartDetail>();try{listPartResponse = await minioHelper.ListPartsUploadInfo(ConfigConstant.MinioBucketName, "micro-elementtest/" + Name, UploadId);Console.WriteLine("查询上传分片列表" + JsonConvert.SerializeObject(listPartResponse));}catch (MinioException e){Log.Error("查询上传分片列表错误: {0}", e.Message);}return Ok(new {  UploadId, listPartResponse });}/// <summary>/// 合并分片/// </summary>/// <param name="files"></param>/// <returns></returns>[HttpPost("/file/ChunkMultipartUpload")]public async Task<dynamic> ChunkUploadFile( string Name, string UploadId = "", List<PartETag> partETagList=null ){CompleteMultipartUploadResponse compResponse=new CompleteMultipartUploadResponse();try{// Complete the multipart upload  分片上传完后合并compResponse = await minioHelper.CompleteMultipartUploadFile(ConfigConstant.MinioBucketName, "micro-elementtest/" + Name, UploadId, partETagList);Console.WriteLine("分片上传"+ JsonConvert.SerializeObject(compResponse.Key));}catch (MinioException e){Log.Error("文件上传错误: {0}", e.Message);}return Ok(new {  compResponse });}/// <summary>/// 上传分片/// </summary>/// <param name="files"></param>/// <returns></returns>[HttpPost("/file/ChunkUploadFile")]public async Task<dynamic> ChunkUploadFile(IFormFile files, [FromForm] string ID, [FromForm]  string Name, [FromForm] long Size, [FromForm] long partSize,  [FromForm] int ChunkCount, [FromForm] string UploadId = ""){List<PartETag> partETagList = new List<PartETag>();try{// Define input streamStream inputStream = files.OpenReadStream(); //Create13MBDataStream();if (string.IsNullOrWhiteSpace(UploadId)){//初始化分片上传,得到UploadIdUploadId = await minioHelper.InitMultipartChunkUploadFile(ConfigConstant.MinioBucketName, "micro-elementtest/" + Name);}PartETag partETag = await minioHelper.ChunkUploadAsync(ConfigConstant.MinioBucketName, "micro-elementtest/" + Name, UploadId, ChunkCount, partSize, inputStream);partETagList.Add(partETag);}catch (MinioException e){Log.Error("文件上传错误: {0}", e.Message);}return Ok(new { UploadId, partETagList, Name });}

6.前端页面,采用的vue2+element-ui的框架

<template><div><el-upload class="upload-demo" drag action="" multiple :http-request="handHttpRequest"><i class="el-icon-upload"></i><div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div><div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div></el-upload></div>
</template><script>
import { ChunkUploadFileApi } from '@/api/upload'
export default {name: 'uploadPage',data() {return {uploadId: '',ETag1: '',ETag2: '',}},methods: {handtap() {},async handHttpRequest(params) {var chunkSize = 5 * 1024 * 1024 // 1MB一片const name = params.file.namelet UploadId = ''const uploadNextChunk = async (i) => {const file = this.getChunkInfo(params.file, i, chunkSize)console.log(file)const partSize = file.chunk.sizeconst ChunkCount = i+1const res = await ChunkUploadFileApi(file.chunk, '123123123123123sa', name, partSize, ChunkCount, 123154545, UploadId)console.log(res)UploadId = res.uploadIdif (i < 1) {// 仅上传两片,根据需求修改await uploadNextChunk(i + 1)}}await uploadNextChunk(0)},getChunkInfo(file, currentChunk, chunkSize) {var start = currentChunk * chunkSizevar end = Math.min(file.size, start + chunkSize)var chunk = file.slice(start, end)return {start,end,chunk,}},},
}
</script><style></style>

upload文件内容为

import request from '@/utils/request'//这个是request
import base from '@/api/base'//这个是我自己文件的api前缀const noteApi = {ChunkUploadFile: base.outApi + '/file/ChunkUploadFile', //
}/*** 分片测试* @returns*/
export const ChunkUploadFileApi = (file, hash, name, partSize, ChunkCount, size, UploadId) => {const formData = new FormData();formData.append("files", file);formData.append("Name", name);formData.append("ID", hash);formData.append("PartSize", partSize);formData.append("ChunkCount", ChunkCount);formData.append("Size", size);formData.append("UploadId", UploadId);return request({url: noteApi.ChunkUploadFile,method: "post",data: formData,headersType: "multipart/form-data",});};

7.在前端页面上传分片文件

我这里分片是以5MB为一个分片,超过5MB才使用分片的功能
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
通过接口看到上传成功了

8.通过ListPartsFile方法查询已上传的分片

在这里插入图片描述
上传的分片这时候在minio的web控制台是看不到的,需要去minio的存储文件夹里查看路径/data/.minio.sys/multipart
在这里插入图片描述
在这里插入图片描述

9.合并分片

在这里插入图片描述

在这里插入图片描述
合并后在minio桶里可以看到文件了
在这里插入图片描述

10.注意点:

ConfigConstant.MinioBucketName是minio的存储桶名称,这里示例值是micro-element
ConfigConstant.MinioUserName是minio的AccessKey,值以你自己minio服务器的AccessKey为准
ConfigConstant.MinioPassWord是minio的SecretKey,值以你自己minio服务器的SecretKey为准
ConfigConstant.MinioAddressIp是minio的地址,需要带http://ip:port,比如http://192.168.110.11/

1.文件只有大于5MB才能使用分片,如果小于5MB,则不可以使用分片功能

2.文件分片的流程是:先初始化通过InitMultipartChunkUploadFile接口获取uploadID==>通过ChunkUploadAsync接口上传分片的文件(只有最后一片允许小于5MB,前面的分片必须要等于5MB)==>通过CompleteMultipartUploadFile接口合并分片

3.上传分片后还没有合并前,分片文件在桶里不可见,因为分片文件在你的minio存储路径的/minio/data/.minio.sys/multipart路径下

4.合并后文件建议取CompleteMultipartUploadFile接口返回值的key相对路径,如果取绝对路径location的话,以后迁移服务器会使用崩溃~

5.现在已经有了分片的教程,后续的大文件秒传、断点续传可以根据上面的封装接口举一反三,很简单~
(秒传就是判断文件的md5和size大小合并查询数据库是否有重复,如果有,则直接返回文件信息)
(断点续传就是判断文件的md5和size在数据库是否存在并且未上传完成,则根据已上传的文件去判断还有哪些文件没有上传,直接续传即可)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/56865.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#学习笔记(九)

C#学习笔记&#xff08;九&#xff09; 第六章 面向对象编程&#xff08;一&#xff09;类与对象、字段与属性一、类与对象正确的理解1. 什么是类&#xff1f;2.什么是对象&#xff1f;3. 类与对象的区别 二、类的基本规范和对象使用1. 类的规范 三、类的访问修饰符&#xff08…

GoFly快速开发框架的utils-plugin扩展包开发演示教程

说明 本插件是教大家如何开发框架utils->plugin下扩展插件包&#xff0c;在开发时可安装本插件&#xff0c;参考本插件代码结构写你插件&#xff0c;这样可以达到规范插件代码&#xff0c;同时也也是为了兼容你安装其他人在代码仓通过扩展插件包&#xff0c;如果不规范可能…

Bolt 一款AI 全栈 Web 在线开发工具

参考&#xff1a; https://bolt.new/ github项目也可以支持Bolt在线打开编辑 直接连接前输入&#xff0c;比如 https://github.com/lyz1810/live2dSpeek更换成 https://bolt.new/github.com/lyz1810/live2dSpeek https://bolt.new/github.com/oh-my-live2d/oh-my-live2d 主要偏…

eUSB2规范介绍

一、说明 eUSB的全称是Embedded USB2,也支持低速、全速和高速三个速率,不过降低了电压幅值,从而使SOC更小、功耗更低,主要应用在芯片间互联,如需应用在设备间传输,一般需要加中继器。 eUSB2还支持USB2.0协议,仅物理层要求不同。 eUSB2支持2个模式:原生模式(native m…

[C#][winform]基于yolov8的道路交通事故检测系统C#源码+onnx模型+评估指标曲线+精美GUI界面

【重要说明】 该系统以opencvsharp作图像处理,onnxruntime做推理引擎&#xff0c;使用CPU进行推理&#xff0c;适合有显卡或者没有显卡windows x64系统均可&#xff0c;不支持macOS和Linux系统&#xff0c;不支持x86的windows操作系统。由于采用CPU推理&#xff0c;要比GPU慢。…

Turn-it:调整它:优化线材重构雕塑制造

&#x1f428;文章摘要abstract 电线雕塑在工业应用和日常生活中都很重要。 本文提出了一种新的制造策略&#xff0c;通过调整目标形状以适应电线弯曲机&#xff0c;然后由人工将其弯曲回目标形状。&#xff08;机器弯曲人工弯曲&#xff09; 该方法通过两阶段弯曲策略实现&a…

王爽汇编语言第三版实验2

实验任务 (1)使用Debug&#xff0c;将下面的程序段写 入程序&#xff0c;逐条进行&#xff0c;根据指令执行后的实际运行情况填空。 mov ax,ffff mov ds,ax mov ax,2200 mov ss,ax mov sp,0100 mov ax,[0] ;axC0EAH add ax,[2] ;axCOFCH mov bx,[4] ;bx30F0H add …

Flink消费Kafka实时写入Doris

本文模拟实际生产环境&#xff0c;通过FileBeat采集日志信息到Kafka&#xff0c;再通过Flink消费Kafka实时写入Doris。 文章目录 Filebeat采集日志到KafkaFlink消费Kafka实时写入Doris总结 Filebeat采集日志到Kafka 常见的日志采集工具有以下几种&#xff1a;Flume、Logstash和…

基于SpringBoot+Vue+uniapp微信小程序的校园反诈骗微信小程序的详细设计和实现(源码+lw+部署文档+讲解等)

项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…

Unity 从零开始搭建一套简单易用的UGUI小框架 功能撰写与优化篇

Unity 从零开始搭建一套简单易用的UGUI小框架 基础分析篇-CSDN博客 开始撰写 从基础分析篇我们得到了三个类&#xff0c;面板基类&#xff0c;管理类和面板子类 那就从面板基类开始&#xff0c;定义其基本行为 面板基类 基本方法都很简单&#xff0c;分别是首次加载并打开…

[含文档+PPT+源码等]精品基于springboot实现的原生微信小程序小区兼职系统

基于Spring Boot实现的原生微信小程序小区兼职系统背景&#xff0c;可以从以下几个方面进行阐述&#xff1a; 一、技术背景 移动互联网的普及&#xff1a;随着移动互联网的快速发展&#xff0c;微信小程序作为一种轻量级应用&#xff0c;因其无需下载安装、即用即走的特点&am…

SSD |(七)FTL详解(中)

文章目录 &#x1f4da;垃圾回收&#x1f407;垃圾回收原理&#x1f407;写放大&#x1f407;垃圾回收实现&#x1f407;垃圾回收时机 &#x1f4da;解除映射关系&#x1f4da;磨损均衡 &#x1f4da;垃圾回收 &#x1f407;垃圾回收原理 ✋设定一个迷你SSD空间&#xff1a; 假…

解决ImageIO无法读取部分JPEG格式图片问题

解决ImageIO无法读取部分JPEG格式图片问题 问题描述 我最近对在线聊天功能进行了一些内存优化&#xff0c;结果在回归测试时&#xff0c;突然发现有张图片总是发送失败。测试同事把问题转到我这儿来看&#xff0c;我仔细检查了一下&#xff0c;发现是上传文件的接口报错&#…

获取非加密邮件协议中的用户名和密码——安全风险演示

引言 在当今的数字时代,网络安全变得越来越重要。本文将演示如何通过抓包工具获取非加密邮件协议中的用户名和密码,以此说明使用非加密协议的潜在安全风险。通过这个演示,我们希望能提高读者的安全意识,促使大家采取更安全的通信方式。 注意: 本文仅用于教育目的,旨在提高安全…

Android开发蒙版引导操作功能

Android开发蒙版引导操作功能 复杂的功能&#xff0c;往往需要在上面加一层蒙版引导用户操作 一、思路&#xff1a; 堆积布局方式 二、效果图&#xff1a; 三、关键代码&#xff1a; <?xml version"1.0" encoding"utf-8"?> <FrameLayout x…

【大模型】AI视频课程制作工具开发

1. 需求信息 1.1 需求背景 讲师们在制作视频的过程中&#xff0c;发现录制课程比较麻烦&#xff0c;要保证环境安静&#xff0c;保证录制过程不出错&#xff0c;很容易反复重复录制&#xff0c;为了解决重复录制的工作量&#xff0c;想通过 ai 课程制作工具&#xff0c;来解决…

飞机大战告尾

参考 PPO算法逐行代码详解 链接 通过网盘分享的文件&#xff1a;PlaneWar 链接: https://pan.baidu.com/s/1cbLKTcBxL6Aem3WkyDtPzg?pwd1234 提取码: 1234 10.17关于博客发了又改这件事 悲催的事 今天训练了一早上ppo模型&#xff0c;满怀期待的检测成果时发现一点长进都…

【Linux】“echo $变量“ 命令打印变量值的底层原理

在 shell 中&#xff0c;echo $变量 命令的工作原理涉及几个关键步骤&#xff0c;主要是由 shell 解释器来处理变量的查找和替换。以下是详细的过程&#xff1a; 变量展开的过程顺序 变量引用&#xff1a; 在命令行中&#xff0c;变量通常以 $variable_name 或 ${variable_…

使用Shell脚本对Java应用等服务进行启停控制(支持批量)

通过shell脚本对Java服务启停进行控制。支持单个服务和多个服务的 start、stop、status、restart。支持自定义启动命令。(不限于Java服务,适用于各类通过命令行启动的服务) 脚本名称为 runjar.sh , 底部提供源码。通过三部分进行说明:操作说明、维护自定义服务列表、脚本源…

搭建`mongodb`副本集-开启权限认证 mongo:7.0.5

搭建mongodb副本集-开启权限认证 mongo:7.0.5 1.5.1、创建文件 创建配置文件保存目录和数据保存目录 mkdir -p /data/mongodb/{/conf,/data,/logs}生成和设置权限 这个文件一定要在一个服务里面生成然后复制到其它服务器&#xff0c;所有服务器的这个key一定是相同的。 op…