深入理解文件上传下载的原理及实现逻辑

文件上传下载原理及实现

  • 一、文件上传原理
    • 1.1、http请求格式
    • 1.2、服务器解析
  • 二、文件上传类型
    • 2.1、秒传
    • 2.2、分片上传
    • 2.3、大文件上传
    • 2.4、断点续传
  • 三、断点下载原理
  • 四、多线程下载逻辑
  • 总结

一、文件上传原理

1.1、http请求格式

文件上传的是根据 http 协议的规范和定义,完成请求消息体的封装和消息体的解析,然后将二进制内容保存到文件。
在上传一个文件时,需要把 form 标签的enctype设置为multipart/form-data,同时method必须为post方法

multipart/form-data结构:

# 请求标头
Content-Type: multipart/form-data; boundary=----webKitFormBoundaryDCntfiXcSkPhS4PN
origin: https://convertio.co
referer: https://convertio.co/

# From data
----WebKitFormBoundaryDCntfiXcSkPhS4PN
content-Disposition: form-data; name="f1"; filename="test.gif"Content-Type: image/gif

----WebKitFormBoundaryDCntfiXcSkPhS4PN

(1)请求头(注意这里的请求头并不是指http header):
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryDCntfiXcSkPhS4PN 表示本次请求要上传文件,其中 boundary 表示分隔符,如果要上传多个表单项,就要使用 boundary 分割,每个表单项由----XXX 开始,以----XXX 结尾。

(2)消息体- Form Data 部分:
每一个表单项又由Content-Type和Content-Disposition组成。
Content-Disposition: form-data 为固定值,表示一个表单元素,name 表示表单元素的 名称,回车换行后面就是name的值,如果是上传文件就是文件的二进制内容。
Content-Type:表示当前的内容的 MIME 类型,是图片还是文本还是二进制数据。

1.2、服务器解析

客户端发送请求到服务器后,服务器会收到请求的消息体,然后对消息体进行解析,解析出哪是普通表单哪些是附件。

二、文件上传类型

2.1、秒传

(1)概念:
通俗的说,把要上传的东西上传,服务器会先做MD5校验,如果服务器上有一样的东西,它就直接给个新地址,引用计数加一;其实下载的都是服务器上的同一个文件,想要不秒传,其实只要让MD5改变,就是对文件本身做一下修改(改名字不行),例如一个文本文件,多加几个字,MD5就变了,就不会秒传了。

(2)秒传核心逻辑:

  1. 利用redis的set方法存放文件上传状态,其中key为文件上传的md5,value为是否上传完成的标志位。
  2. 当标志位true为上传已经完成,此时如果有相同文件上传,则进入秒传逻辑。如果标志位为false,则说明还没上传完成,此时需要在调用set的方法,保存块号文件记录的路径,其中key为上传文件md5加一个固定前缀,value为块号文件记录路径。

2.2、分片上传

(1)概念:
分片上传,就是将所要上传的文件,按照一定的大小,将整个文件分隔成多个数据块(称之为Part)来进行分别上传,上传完之后再由服务端对所有上传的文件进行汇总整合成原始的文件。

(2)分片上传的场景:

  1. 大文件上传。
  2. 网络环境环境不好,存在需要重传风险的场景。
初始化文件块大小和序号
计算当前块文件起始位置
是否上传完分片
读取分片的文件内容位置
追加分片内容和分片序号
上传文件
上传成功,返回200
分片序号加一
请求合并
上传完毕

2.3、大文件上传

大文件上传一般采用分片上传的方式,这样可以提高文件上传的速度,前端拿到文件流后进行分片,然后与后端进行通讯传输,一般还会结合断点继传,这时后端一般提供三个接口:

  1. 第一个接口获取已经上传的分片信息。
  2. 第二个接口将前端分片文件进行传输。
  3. 第三个接口是将所有分片上传完成后告诉后端进行文件合并。
服务端
客户端:分片
切片文件
切片文件
切片文件
切片文件
最后的切片文件
Part
Part
Part
....
切片整合
Part
Part
Part
Part
....
Part

2.4、断点续传

(1)概念:
断点续传是在下载或上传时,将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传或者下载未完成的部分,而没有必要从头开始上传或者下载。

(2)应用场景:
断点续传可以看成是分片上传的一个衍生,因此可以使用分片上传的场景,都可以使用断点续传。

(3)实现断点续传的核心逻辑:
在分片上传的过程中,如果因为系统崩溃或者网络中断等异常因素导致上传中断,这时候客户端需要记录上传的进度。在之后支持再次上传时,可以继续从上次上传中断的地方进行继续上传。
为了避免客户端在上传之后的进度数据被删除而导致重新开始从头上传的问题,服务端也可以提供相应的接口便于客户端对已经上传的分片数据进行查询,从而使客户端知道已经上传的分片数据,从而从下一个分片数据开始继续上传。

(4)实现流程步骤:
方案一(检测分片的方式):

  1. 将需要上传的文件按照一定的分割规则,分割成相同大小的数据块;
  2. 初始化一个分片上传任务,返回本次分片上传唯一标识;
  3. 按照一定的策略(串行或并行)发送各个分片数据块;
  4. 发送完成后,服务端根据判断数据上传是否完整,如果完整,则进行数据块合成得到原始文件。

方案二(检测文件大小的方式):

  1. 前端(客户端)需要根据固定大小对文件进行分片,请求后端(服务端)时要带上分片序号和大小。
  2. 服务端创建conf文件用来记录分块位置,conf文件长度为总分片数,每上传一个分块即向conf文件中写入一个127,那么没上传的位置就是默认的0,已上传的就是Byte.MAX_VALUE 127(这步是实现断点续传和秒传的核心步骤)。
  3. 服务器按照请求数据中给的分片序号和每片分块大小(分片大小是固定且一样的)算出开始位置,与读取到的文件片段数据,写入文件。

三、断点下载原理

  1. 获取服务器文件的大小;
  2. 发起下载请求,包含下载范围。比如总文件大小为1024,已经下载了238,要下载的范围就是239~1024;服务器按照请求的范围发送给客户端。

获取文件大小:如果使用curl开源库,可以通过curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD,&size)获取文件的大小。

四、多线程下载逻辑

  1. 先获取文件大小。
  2. 根据线程数量划分每个线程要下载的文件长度;不能整除则采用向上取整。
  3. 每个线程下载对应的区域块。
  4. 顺序合并文件;写入时候加锁,lseek到对应位置,然后写入数据。

一般,顺序合并文件是要先等前面序号的下载完,后面序号(比前面序号的先下载完)的才会整合进来。
多线程下载要不要临时文件,依赖于业务要求,如果是大文件的最好有临时文件,减少内存占用。

总结

本文全面介绍了文件上传下载的原理和实现逻辑。首先学习了文件上传的基本原理,包括HTTP请求格式和服务器解析过程。然后深入探讨了不同类型的文件上传,如秒传、分片上传、大文件上传和断点续传。对于文件下载,解释了断点下载的原理,并介绍了多线程下载的逻辑。

通过本文的学习,对文件上传下载有了更深入的了解。了解了文件上传的工作原理,以及不同类型的文件上传方式的特点和应用场景。对于文件下载,学习了断点下载的原理和多线程下载的逻辑。这些知识可以帮助更好地应用和优化文件传输功能,提高系统性能和用户体验。

在未来的工作中,可以根据不同的需求选择合适的文件上传方式,并结合断点下载和多线程下载等技术,提升文件传输的效率和速度。同时,还可以深入研究和应用其他相关的文件传输技术,不断优化系统的文件传输功能,以满足用户对高效、稳定文件传输的需求。
深入理解文件上传下载的原理及实现逻辑_第1张图片

你可能感兴趣的:(图床项目,服务器,数据库,FastDFS,后端,linux,http,https)