Java如何实现大文件分片上传,断点续传和秒传
- 引言
- 概念
- 秒传
- 1、什么是秒传
- 2、实现秒传常见做法
- 分片上传
- 1、什么是分片上传
- 2、分片上传的场景
- 断点续传
- 1、什么是断点续传
- 2、应用场景
- 3、实现断点续传的核心逻辑
- 秒传
- 实现思路
- 前置知识
- 源码
- 参考
引言
关于文件上传模块,主要难点还是集中在大文件上传,毕竟我们无法确保在一个http连接中,能够将一个大文件完整传输过来,特别是在网络环境不稳定的情况下,如果是这样的话,一旦传输过程中出现错误,那就意味着需要重新传输整个文件,相信这是我们都不希望看到的局面,而本文就是来介绍打破这种局面的办法。
首先,还是先把分片上传,断点续传和秒传这些概念弄清楚。
概念
秒传
1、什么是秒传
通俗的说,你把要上传的东西上传,服务器会先做 MD5 校验,如果服务器上有同样的东西,它就直接给你个新地址,其实你下载的都是服务器上的同一个文件,想要不秒传,其实只要让 MD5 改变,就是对文件本身做一下修改(改名字不行),例如一个文本文件,你多加几个字,MD5 就变了,就不会秒传了.
2、实现秒传常见做法
a、利用 redis 的 set 方法存放文件上传状态,其中 key 为文件上传的 md5,value 为是否上传完成的标志位;
b、当标志位为 true 表示上传已经完成,此时如果有相同文件上传,则进入秒传逻辑。如果标志位为 false,则说明还没上传完成,此时需要再调用 set 方法,保存块号文件记录的路径,其中 key 为上传文件的 md5 一个固定前缀,value 为块号文件的记录路径
分片上传
1、什么是分片上传
分片上传,就是将所要上传的文件,按照一定的大小,将整个文件分隔成多个数据块(我们称之为 Part)来进行上传,上传完之后再由服务端对所有上传的文件进行汇总整合成原始的文件。
2、分片上传的场景
1.大文件上传
2.网络环境环境不好,存在需要重传风险的场景
断点续传
1、什么是断点续传
断点续传是在下载或上传时,将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传或者下载未完成的部分,而没有必要从头开始上传或者下载。
PS:本文的断点续传主要是针对断点上传场景。
2、应用场景
断点续传可以看成是分片上传的一个衍生,因此可以使用分片上传的场景,都可以使用断点续传。
3、实现断点续传的核心逻辑
在分片上传的过程中,如果因为系统崩溃或者网络中断等异常因素导致上传中断,这时候客户端需要记录上传的进度。在之后支持再次上传时,可以继续从上次上传中断的地方进行继续上传。
为了避免客户端在上传之后的进度数据被删除而导致重新开始从头上传的问题,服务端也可以提供相应的接口便于客户端对已经上传的分片数据进行查询,从而使客户端知道已经上传的分片数据,从而从下一个分片数据开始继续上传。
实现思路
- 前端对文件进行MD5加密,并且将文件按一定的规则分片
- 前端发送get请求校验分片数据在服务端是否完整,如果完整则进行秒传,如果不完整或者无数据,则进行分片上传。
- 后台校验MD5值,根据上传的序号和分片大小计算相应的开始位置并写入该分片数据到文件中。
前置知识
这里只讲用java后端实现文件上传时会遇到的一些坑和前置知识:
- RandomAccessFile文件随机读写流,这个类比较简单,大家自行了解一下即可
- MappedByteBuffer文件内存映射,底层通过mmap实现, 通过将文件直接映射到用户空间,可以减少系统调用和内存拷贝次数,从而大大提高大文件传输性能,具体使用和原理大家参考此篇文章: 神奇的MappedByteBuffer
- 加密算法: java——加密、解密算法
因为我是直接使用java来mock客户端的,因此就选用了RestTemplate来作为发送请求的工具,但是使用RestTemplate来发送文件时,存在一些小坑,大家需要注意,具体如何使用RestTemplate发送文件,大家可以参考此篇文章:
使用RestTemplate上传文件
源码
源码大家自行从仓库下载查看,就不在文中粘贴源码了。
源码仓库
参考
实战篇:手撸大文件上传
https://gitee.com/KT1205529635/simple-uploader