【.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.rhkb.cn/news/446425.html

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

相关文章

使用CSS和HTML实现3D图片环绕效果

使用CSS和HTML实现3D图片环绕效果 在本篇博客中&#xff0c;将介绍如何使用HTML和CSS实现一个3D图片环绕效果。这个效果不仅具有视觉吸引力&#xff0c;而且具有高度的互动性&#xff0c;鼠标悬停时动画会暂停。接下来将一步步讲解这个效果的实现过程。 1. 效果 2. 页面结构与…

【华为HCIP实战课程十一】OSPF网络NBMA网络解决方案,网络工程师

上节我们讲解了DR DBR 选举,每台设备可以学到全网路由,但是通信是有问题的 DR BDR的选举是基于接口的,而不是基于路由器的 一、OSPF路由通信问题 R5虽然可以学到全网的OSPF路由,但是R5无法ping通44.1.1.1 原因是R5到达R4 lo0的下一跳是10.1.1.4, 而R5和R4直连无法ping通…

数码准备记录

1.数据结构 常见的数据结构包括数组、链表、栈、队列、树&#xff08;如二叉树、B树、B树&#xff09;、图等 2.队列和栈的区别 队列是一种先入先出的数据结构&#xff0c;即最先加入的元素被最先移除&#xff1b; 栈是一种后进后出的数据结构&#xff0c;即最后加入的元素…

linux tar 打包文件去掉文件所在路径

一、准备目录 /root/tmp/images /root/tmp/images2 执行命令打包目录/root/tmp/images 到 /root/tmp/images.tar.gz 再解压到/root/tmp/images2 cd /root/tmp/images && tar -cvzf images.tar.gz * && mv images.tar.gz /root/tmp/ tar -C /root/tmp/image…

JDK17常用新特性

目前国内大部分开发人员都是在使用jdk8&#xff0c;甚至是jdk6&#xff0c;但是随着jdk的更新迭代&#xff0c;jdk8我觉得可能就会慢慢的淡出舞台&#xff0c;随着目前主流框架最新版推出明确说明了不再支持jdk8&#xff0c;也促使我不得不抓紧学习了解一波jdk17的新特性&#…

多线程-初阶(2)BlockingQueueThreadPoolExecutor

学习目标&#xff1a; 熟悉wait和notify的线程休眠和启动 熟悉多线程的基本案例 1.单例模式的两种设置模式:懒汉模式和饿汉模式 2.阻塞队列(生产者消费者模型) 3.线程池 4.定时器 1.wait和notify 由于线程之间是抢占式执⾏的, 因此线程之间执⾏的先后顺序难以预知. 但是…

【消息队列】Kafka从入门到面试学习总结

国科大学习生活&#xff08;期末复习资料、课程大作业解析、大厂实习经验心得等&#xff09;: 文章专栏&#xff08;点击跳转&#xff09; 大数据开发学习文档&#xff08;分布式文件系统的实现&#xff0c;大数据生态圈学习文档等&#xff09;: 文章专栏&#xff08;点击跳转&…

人工智能的核心技术之机器学习

大家好&#xff0c;我是Shelly&#xff0c;一个专注于输出AI工具和科技前沿内容的AI应用教练&#xff0c;体验过300款以上的AI应用工具。关注科技及大模型领域对社会的影响10年。关注我一起驾驭AI工具&#xff0c;拥抱AI时代的到来。 人工智能&#xff08;AI&#xff09;核心技…

使用DataX同步hive数据到MySQL

目录 1、组件环境 2、安装datax 2.1、下载datax并解压 3、安装datax-web 3.0、下载datax-web的源码&#xff0c;进行编译 3.1、在MySQL中创建datax-web元数据 3.2、安装data-web 3.2.1执行install.sh命令解压部署 3.2.1、手动修改 datax-admin配置文件 3.2.2、手动修改…

「Ubuntu」文件权限说明(drwxr-xr-x)

我们在使用Ubuntu 查看文件信息时&#xff0c;常常使用 ll 命令查看&#xff0c;但是输出的详细信息有些复杂&#xff0c;特别是 类似与 drwxr-xr-x 的字符串&#xff0c;在此进行详细解释下 属主&#xff1a;所属用户 属组&#xff1a;文件所属组别 drwxr-xr-x 7 apps root 4…

Pytorch基础:设置随机种子

相关阅读 Pytorch基础https://blog.csdn.net/weixin_45791458/category_12457644.html?spm1001.2014.3001.5482 有时候&#xff0c;如果需要代码在多个运行中具有可重复性&#xff0c;可以通过以下方式来设置随机种子&#xff1a; import torch import numpy as np import r…

【亲测可行】最新ubuntu搭建rknn-toolkit2

文章目录 🌕结构图(ONNX->RKNN)🌕下载rknn-toolkit2🌕搭建环境🌙配置镜像源🌙conda搭建python3.8版本的虚拟环境🌙进入packages目录安装依赖库🌕测试安装是否成功🌕其它🌙rknn-toolkit2🌙rknn_model_zoo🌙关于部署的博客发布本文的时间为2024.10.13…

【进阶OpenCV】 (11)--DNN板块--实现风格迁移

文章目录 DNN板块一、DNN特点二、DNN函数流程三、实现风格迁移1. 图像预处理2. 加载星空模型3. 输出处理 总结 DNN板块 DNN模块是 OpenCV 中专门用来实现 DNN(Deep Neural Networks,深度神经网络) 模块的相关功能&#xff0c;其作用是载入别的深度学习框架(如 TensorFlow、Caf…

【微信小程序_11_全局配置】

摘要:本文介绍了微信小程序全局配置文件 app.json 中的常用配置项,重点阐述了 window 节点的各项配置,包括导航栏标题文字、背景色、标题颜色,窗口背景色、下拉刷新样式以及上拉触底距离等。通过这些配置可实现小程序窗口外观的个性化设置,提升用户体验。 微信小程序_11_全…

如何成为 Rust 核心贡献者?Rust 开发的核​​心是什么?Rust 重要技术专家揭秘

10 月 17 - 18日&#xff0c;由 GOSIM 开源创新汇主办、CSDN 承办的 GOSIM CHINA 2024 将在北京盛大启幕。作为 GOSIM 开源年度大会的第三届盛会&#xff0c;本次活动邀请了 60 多位国际开源专家&#xff0c;汇聚了来自全球百余家顶尖科技企业、知名高校及开源社区的技术大咖、…

回溯法与迭代法详解:如何从手机数字键盘生成字母组合

在这篇文章中&#xff0c;我们将详细介绍如何基于手机数字键盘的映射&#xff0c;给定一个仅包含数字 2-9 的字符串&#xff0c;输出它能够表示的所有字母组合。这是一个经典的回溯算法问题&#xff0c;适合初学者理解和掌握。 问题描述 给定一个数字字符串&#xff0c;比如 …

python基础路径的迁移

本人未安装anaconda或pycharm等&#xff0c;仅安装了某个python环境&#xff0c;因此以下方法仅针对基础python环境的迁移&#xff0c;不确保其他软件或插件正常运行 第一步将原python路径的整个文件夹剪切到新的路径下 第二步修改系统环境变量&#xff0c;将原来的python路径…

php 生成随机数

记录&#xff1a;随机数抽奖 要求&#xff1a;每次生成3个 1 - 10 之间可重复&#xff08;或不可重复&#xff09;的随机数&#xff0c;10次为一轮&#xff0c;每轮要求数字5出现6次、数字4出现3次、…。 提炼需求&#xff1a; 1&#xff0c;可设置最小数、最大数、每次抽奖生…

鸿蒙--商品列表

这里主要利用的是 List 组件 相关概念 Scroll:可滚动的容器组件,当子组件的布局尺寸超过父组件的视口时,内容可以滚动。List:列表包

AI+若依框架day02

项目实战 项目介绍 帝可得是什么 角色和功能 页面原型 库表设计 初始AI AIGC 提示工程 Prompt的组成 Prompt练习 项目搭建 点位管理 需求说明 库表设计