版式文件 流式文件_在.NetCore中实现流式大文件上传

74ad4d65b0656eb42cd8b6aef909f63d.png

大家好,今天给大家分享一下关于大文件上传的时候使用到的一些方法和技巧。在现实的需求当中,经常会用到文件的上传,如用户头像的更换、数据报表的导入或网站后台的上传视频等,都离不开文件的上传。注:本文所用IDE为Rider。

一、单个普通文件的上传

1 项目层级图

f6805d88f628502de9be8af29bd632d1.png

2   控制器方法,[FromForm] IFormFile 参数绑定

69a3adf6a319c32a3aa1bf463a481dd2.png

3 上传文件逻辑

cb6d44d7f6b7eb303dd241e3493a0340.png

使用微软推荐的IFormFile 来接收用户传进的文件,这里是整个文件读入IFormFile,它是文件的C#表现形式,用于处理或者保存文件。

二、解析流式上传文件

客户端选择一个文件进行上传,我们客户端在和服务端进TCP的三次握手过程之后,(如下图)连接通道就正式打开了。既然前面我们能够读到file.Length的,那么它肯定是完全传输完成之后,我们才可以进行读取它的长度。由于此过程是写入我们的内存的,因此是比较吃我们的内存,如果文件过大或者并发进行传文件,那么服务器的内存肯定是吃不消的。

da5a26e018fab454d0a8e5524e3fa75f.png

那么有没有其他的办法呢?答案是肯定的。那就是基于流进行文件传输。如下图所示,当客户端(Client以下简称C)和服务端(Server以下简称S)建立双向通信之后,他们之间就有了一个滑动窗口。那么什么是滑动窗口呢?TCP的可靠数据就是基于滑动窗口协议。

be14695df50353250c3504d7d00912df.png

在TCP建立建立连接之时,双方都为之分配了固定大小的缓存空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这里我们以64kb为例。实现流量控制的方法之一就是采用滑动窗口协议来实现。

假如要传送一个100M的文件,它将会以一个个分包的形式往接收端那里流。那流入到接收端的大小达到64kb满了之后,客户端等待,服务器等待,这个时候不做任何的操作,这时TCP处于连接状态,但是并不传输数据。

这个时候就不存在会塞满服务器的情况,这是协议帮我们完成的,在建立通信之初就会确定好缓存空间的大小,以防溢出。

那在这个等待的过程中呢,客户端看到的就是圈圈一直在转,或者显示上传中。

相关联的应用进程或者其他的任务线程会从缓存中读取数据,但是不一定就是数据一到缓存就开始读取,服务器端的应用也许在忙其他的事情。

那加入一个相关联的进程应用读取了4kb,那还剩下60kb。应用拿到这4kb的数据(其实就是字节序列,流也是有序的字节序列),应用可以帮你做相应的处理,可以打开文件流,把它序列化到硬盘中去,也可以发送到其他的地方。之后C(发送端)会继续流4kb的数据过来。当接收端相关进程读取数据,读到null的时候,那么这个传输就结束了。

三、流式上传文件实现

1)  去除自动绑定模型数据

因为就算不写参数IFormFile,微软默认的机制还是会将我们上传的文件给绑定到Request.Form.Files上去。我们可以利用资源筛选器,在绑定之前或控制器之前进行相关操作,如下图:

6d92941f612437c44f630eabcbc74ebc.png

AttributeTargets.Class和AttributeTargets.Method让其特性标签可针对于类和方法上。方法则是移除掉相关form绑定的操作。

2)  获取解析客户端上传过来的流

string multipartBoundary = Request.GetMultipartBoundary();这个是获取到请求的分隔符。因为在流传输文件的时候,前端标签内容需要严格遵守enctype="multipart/form-data", method=post, type="file" 根据 rfc1867, 这三个属性是必须的。在传输发送的过程中,分隔符用以分隔多个文件或表单项。如果分隔符为null,那说明此次传输就不是一个文件流的传输。

之后进行流的一个读取,如下图所示,将分隔符和传输的body给到读取器,初始化一个MultipartReader。

41e48967a2dc5bbb5c29fa3b84114277.png

之后就开始读,并转存。如下图

a53eb6a945d75bf9f6a30f5d985d0af3.png

如果读取的内容不为null,就尝试转化为file。接着如果file存在,我们就将其流拷贝到内存流中去。如图1-5:可以看到我们对文件加以验证,必须要有内容,且分包流传输的大小也可以控制,因为是在源源不断的进行流的传输,源源不断的进行读取,直至结束。

大家可以看到我红色的标记处,为什么前面进行了格式验证,后面又进行一次验证呢?

286b436b7d8d706269987e14cdcce071.png

大家应该知道,以前QQ中毒,或者被盗号。这里为了安全起见,我们验证了文件的签名,确保其是一个真正的我们需要的文件。因为文件的扩展名是可以更改的,内容却有可能是一个病毒文件,所以需要再次验证其签名。

验证签名的方式,我使用了微软提供的一个代码案例,如下两张图所示:

19b876e514c2351245132f9e4bfe99ea.png

bee1bb2bedc93143096d2ebf3c52c58f.png

上面文件格式的签名只列举了几个,其他的没有的可以去官网查并且加进去。

3)  解析验证完成,进行储存

在这个可怜的流经过重重验证之后,终于可以把这个文件流给拷贝到本地路径了。如下图所示:

7b82191b213e4e79c0c81525689533fb.png

至此,大文件流式上传的方案到此结束,总结一下注意的点:

① 上传大文件时采用流式上传。

② 要注意验证文件的安全性,从签名、扩展名、大小方面验证。

③ 不写参数IFormFile,也会储存到Request.Form.Files。当使用大文件上传时,会严重影响服务器性能和用户体验,可使用资源筛选器进行限制,使用流的方式进行文件的上传。

445b1d522eee1431208d6a8436a09876.png

欢迎关注“新阁上位机编程”抖音号

不定期发布上位机实用小技巧哦

快来学习互粉呀~d72b3e64d25068caa9b64a7f3b381546.png

(长按下方图片?保存到手机相册,打开抖音扫码关注哦!相信你肯定会cdf453e1e7a00c7ff024d4c1b5e818e4.png)

1b2f8ba53aa3da5bcd4050ce2f7a04e2.png

推荐阅读

1、C# 委托、泛型委托与Lambda表达式

2、.NET Core3.1总体预览和第一个Core程序的创建

3、.NetCore程序在Linux上面部署的实现

339ad5ef745c81378383aa03be5bd827.gif
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值