大家好,今天给大家分享一下关于大文件上传的时候使用到的一些方法和技巧。在现实的需求当中,经常会用到文件的上传,如用户头像的更换、数据报表的导入或网站后台的上传视频等,都离不开文件的上传。注:本文所用IDE为Rider。
一、单个普通文件的上传
1 项目层级图
2 控制器方法,[FromForm] IFormFile 参数绑定
3 上传文件逻辑
使用微软推荐的IFormFile 来接收用户传进的文件,这里是整个文件读入IFormFile,它是文件的C#表现形式,用于处理或者保存文件。
二、解析流式上传文件
客户端选择一个文件进行上传,我们客户端在和服务端进TCP的三次握手过程之后,(如下图)连接通道就正式打开了。既然前面我们能够读到file.Length的,那么它肯定是完全传输完成之后,我们才可以进行读取它的长度。由于此过程是写入我们的内存的,因此是比较吃我们的内存,如果文件过大或者并发进行传文件,那么服务器的内存肯定是吃不消的。
那么有没有其他的办法呢?答案是肯定的。那就是基于流进行文件传输。如下图所示,当客户端(Client以下简称C)和服务端(Server以下简称S)建立双向通信之后,他们之间就有了一个滑动窗口。那么什么是滑动窗口呢?TCP的可靠数据就是基于滑动窗口协议。
在TCP建立建立连接之时,双方都为之分配了固定大小的缓存空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这里我们以64kb为例。实现流量控制的方法之一就是采用滑动窗口协议来实现。
假如要传送一个100M的文件,它将会以一个个分包的形式往接收端那里流。那流入到接收端的大小达到64kb满了之后,客户端等待,服务器等待,这个时候不做任何的操作,这时TCP处于连接状态,但是并不传输数据。
这个时候就不存在会塞满服务器的情况,这是协议帮我们完成的,在建立通信之初就会确定好缓存空间的大小,以防溢出。
那在这个等待的过程中呢,客户端看到的就是圈圈一直在转,或者显示上传中。
相关联的应用进程或者其他的任务线程会从缓存中读取数据,但是不一定就是数据一到缓存就开始读取,服务器端的应用也许在忙其他的事情。
那加入一个相关联的进程应用读取了4kb,那还剩下60kb。应用拿到这4kb的数据(其实就是字节序列,流也是有序的字节序列),应用可以帮你做相应的处理,可以打开文件流,把它序列化到硬盘中去,也可以发送到其他的地方。之后C(发送端)会继续流4kb的数据过来。当接收端相关进程读取数据,读到null的时候,那么这个传输就结束了。
三、流式上传文件实现
1) 去除自动绑定模型数据
因为就算不写参数IFormFile,微软默认的机制还是会将我们上传的文件给绑定到Request.Form.Files上去。我们可以利用资源筛选器,在绑定之前或控制器之前进行相关操作,如下图:
AttributeTargets.Class和AttributeTargets.Method让其特性标签可针对于类和方法上。方法则是移除掉相关form绑定的操作。
2) 获取解析客户端上传过来的流
string multipartBoundary = Request.GetMultipartBoundary();这个是获取到请求的分隔符。因为在流传输文件的时候,前端标签内容需要严格遵守enctype="multipart/form-data", method=post, type="file" 根据 rfc1867, 这三个属性是必须的。在传输发送的过程中,分隔符用以分隔多个文件或表单项。如果分隔符为null,那说明此次传输就不是一个文件流的传输。
之后进行流的一个读取,如下图所示,将分隔符和传输的body给到读取器,初始化一个MultipartReader。
之后就开始读,并转存。如下图
如果读取的内容不为null,就尝试转化为file。接着如果file存在,我们就将其流拷贝到内存流中去。如图1-5:可以看到我们对文件加以验证,必须要有内容,且分包流传输的大小也可以控制,因为是在源源不断的进行流的传输,源源不断的进行读取,直至结束。
大家可以看到我红色的标记处,为什么前面进行了格式验证,后面又进行一次验证呢?
大家应该知道,以前QQ中毒,或者被盗号。这里为了安全起见,我们验证了文件的签名,确保其是一个真正的我们需要的文件。因为文件的扩展名是可以更改的,内容却有可能是一个病毒文件,所以需要再次验证其签名。
验证签名的方式,我使用了微软提供的一个代码案例,如下两张图所示:
上面文件格式的签名只列举了几个,其他的没有的可以去官网查并且加进去。
3) 解析验证完成,进行储存
在这个可怜的流经过重重验证之后,终于可以把这个文件流给拷贝到本地路径了。如下图所示:
至此,大文件流式上传的方案到此结束,总结一下注意的点:
① 上传大文件时采用流式上传。
② 要注意验证文件的安全性,从签名、扩展名、大小方面验证。
③ 不写参数IFormFile,也会储存到Request.Form.Files。当使用大文件上传时,会严重影响服务器性能和用户体验,可使用资源筛选器进行限制,使用流的方式进行文件的上传。
![445b1d522eee1431208d6a8436a09876.png](https://img-blog.csdnimg.cn/img_convert/445b1d522eee1431208d6a8436a09876.png)
欢迎关注“新阁上位机编程”抖音号
不定期发布上位机实用小技巧哦
快来学习互粉呀~
(长按下方图片?保存到手机相册,打开抖音扫码关注哦!相信你肯定会)
推荐阅读
1、C# 委托、泛型委托与Lambda表达式
2、.NET Core3.1总体预览和第一个Core程序的创建
3、.NetCore程序在Linux上面部署的实现
![339ad5ef745c81378383aa03be5bd827.gif](https://img-blog.csdnimg.cn/img_convert/339ad5ef745c81378383aa03be5bd827.gif)