JAVA实现大文件多线程下载,提速30倍!想学?我教你啊
前言
在之前文章 中,我们有提到大文件下载和断点续传,本篇我们就来开发一个多线程文件下载器,最后我们用这个多线程下载器来突破云盘下载的限速。
兄弟们看到这个标题可能会觉得是个标题党,为了解决疑虑,我们先来看下最终的测试结果:
测试云盘下载的文件 46M,自己本地最大下载速度 2M
1. 单线程下载,总耗时: 603s2. 多线程下载,50个线程,总耗时:13s
测试结果,「提速46倍」,我还是太谦虚了,只说提速30倍,此处我们觉得应该有掌声(我听不到,还是点赞实在)
HTTP协议Range请求头
Range主要是针对只需要获取部分资源的范围请求,通过指定Range即可告知服务器资源的指定范围。格式: Range: bytes=start-end
比如: 获取字节范围 5001-10000
也可以指定开始位置不指定结束位置,表示获取开始位置之后的全部数据
服务器接收到带有Range的请求,会在处理请求之后返回状态码为206 Partial Content的响应。
基于Range的特性,我们就可以实现文件的多线程下载,文件的断点续传
准备工作
本文我们使用的SpringMVC中的RestTemplate;由于云的链接是Https,所以我们需要设置RestTemplate绕过证书验证
- pom.xml
- 编写RestTemplate的构造器,以及绕过https的证书验证
- 在下载的过程中,我们需要知道当前下载的速度是多少,所以需要定义一个显示下载速度的接口
因为计算下载速度,我们需要知道每秒传输的字节数是多少,为了监控传输数据的过程,我们需要了解SpringMVC中的接口ResponseExtractor
该接口只有一个方法,当客户端和服务器端连接建立之后,会调用这个方法,我们可以在这个方法中监控下载的速度。
- DisplayDownloadSpeed接口的抽象实现 AbstractDisplayDownloadSpeedResponseExtractor
- 整个项目主要涉及到的类图
简单的文件下载器
这里使用的是restTemplate调用execute, 先文件获取到字节数组, 再将字节数组直接写到目标文件。
这里我们需要注意的点是: 这种方式会将文件的字节数组全部放入内存中, 及其消耗资源;我们来看看如何实现。
- 创建ByteArrayResponseExtractor类继承AbstractDisplayDownloadSpeedResponseExtractor
ByteArrayResponseExtractor
- 调用restTemplate.execute执行下载,保存字节数据到文件中
- 测试下载819M的idea
执行一段时间之后,我们可以看到内存已经使用了800M左右,所以这种方式只能使用于小文件的下载,如果我们下载几G的大文件,内存肯定是不够用的。至于下载时间,因为文件太大也没有等下载完成就结束了程序。
单线程大文件下载
上面的方式只能下载小的文件,那大文件的下载我们该用什么方式呢?我们可以把流输出到文件而不是内存中。接下来我们来实现我们大文件的下载。
- 创建FileResponseExtractor类继承AbstractDisplayDownloadSpeedResponseExtractor,把流输出到文件中
- 文件下载器,先把流输出到临时下载文件(xxxxx.download),下载完成后再重命名文件
- 测试下载819M的idea
执行一段时间之后,我们再看看下内存的使用情况,发现这种方式内存消耗较少,效果比较理想,下载时间:199s
多线程文件下载
如果服务器不限速的话,通常能够把自己本地的带宽给跑满,那么使用单线程下载就够了,但是如果遇到服务器限速,下载速度远小于自己本地的带宽,那么可以考虑使用多线程下载。多线程我们使用CompletableFuture(可以参考文章 )。
实现多线程文件下载的基本流程:
- 首先我们通过Http协议的Head方法获取到文件的总大小
- 然后根据设置的线程数均分文件的大小,计算每个线程的下载的字节数据开始位置和结束位置
- 开启线程,设置HTTP请求头Range信息,开始下载数据到临时文件
- 下载完成后把每个线程下载完成的临时文件合并成一个文件
完成代码如下:
- 开启30个线程测试下载819M的idea
从执行的结果上来看,因为开启了30个线程同时在下载,内存的占用要比单线程消耗的多,但是也在接受范围内,下载时间:81s,速度提升2.5倍,这是因为idea的下载服务器没有限速,本次多线程速度的提升仅仅是在充分的压榨本地的带宽,所以提示的幅度不大。
单线程下载和多线程下载对比测试
因为云盘对单个线程的下载速度做了限制,大概是在100kb,所以我们使用云盘的下载链接,来测试多线程和单线程的下载速度。
- 测试 云盘中 46M 的文件的下载速度,自己本地最大下载速度 2M
- 获取文件的下载地址
❝
注意:从浏览器中获取的链接需要先使用URLDecode解码,否则下载会失败,并且云盘文件的下载链接是有时效性的,过期后就不能在下载,需要重新生成下载链接
❞
测试单线程下载文件
执行的结果可以看出,云盘对单线程的下载限速真的是丧心病狂, 46M的文件下载需要耗时: 600s
测试多线程下载文件
为了充分的压榨网速,找出最合适的线程数,所以测试了不同线程数的下载速度
线程数 下载总耗时 10 60s 20 30s 30 21s 40 15s 50 13s
从测试的结果上来看,对于自己的运行环境把线程数设置在30个左右比较合适
文件断点续传如何实现,欢迎在大家评论区说出自己的思路。
写到最后(点关注,不迷路)
文中或许会存在或多或少的不足、错误之处,有建议或者意见也非常欢迎大家在评论交流。
最后,「创作不易,请不要白嫖」,希望朋友们可以「点赞评论关注」三连,因为这些就是我分享的全部动力来源
❝
本文纯粹用于学习
评论区回复 「源码」 私发给大家源码地址
喜欢请记得star哦
❞
JAVA WEB 实现文件上传和下载接口功能
JAVA WEB 实现文件上传和下载接口功能,百度webuploader上传文件到服务器指定文件夹问题,webuploader上传文件到服务器指定文件夹问题,JSP上传文件到服务器指定文件夹问题,JAVA上传大文件实现源代码,JAVA上传大文件实现源码,JAVA上传大文件实现代码,JAVA上传大文件实现技巧,JAVA上传大文件实现技术,JAVA上传大文件实现思路,JAVA上传大文件实现解决方案,前端上传大文件实现方案,js上传大文件实现方法,JavaScript上传大文件实现方法,vue上传大文件实现方法,前端上传大文件实现方法,html上传大文件实现方法,html5上传大文件实现方法,百度webuploader上传大文件实现方法,webuploader上传大文件实现方法,JAVA上传大文件实现方法,
文件比较大,有50G左右,用户希望能够在网页里面直接上传,一期的时候我们是直接用的HTML5的API,也就是chrome提供的API来做的,但是上线后用户反馈不是特别的好用,用户那边有些电脑用的是WIN7+IE9,chrome的API在ie9里面不支持。但是用户系统是支持的,这就把人整的有点不会了。二期的时候我们还是定制开发了,
前端用了JSP,VUE2,VUE3,后端用了JSP,SpringBoot,IDE用了Eclipse,MyEclipse,因为新项目和老项目都用了两种IDE。
用户要求能够在网页上面上传文件夹,文件夹里面大约有1万多个文件,有大有小,大的有1G~10G,小的有几MB,文件夹上传的时候需要保存层级结构,同时能够将层级结构信息保存到数据库中,同时还需要支持文件夹下载,下载下来的文件夹要和上传的文件夹层级结构一模一样。
要求支持断点续传,支持进度信息离线存储,用户可能传一半没有传完,下班了,明天上班后继续上传,电脑晚上到点需要关机,支持加密传输,支持国密加密算法SM4,要求支持下载,支持非打包方式下载,浏览器要求支持包含IE在内的所有浏览器,
系统环境要求支持信创国产化,比如银河麒麟,中标麒麟,统信UOS,龙芯,数据库支持MySQL,Oracle,达梦数据库,人大金仓,需要提供前端源码,后端源码,控件源码,公司自己的项目,也有自己的产品,后续需要集成使用,
要求提供7*24小时技术支持服务,提供文档教程,视频教程,远程技术指导,1对1技术支持服务,提供手机,微信,QQ,邮箱,企业微信等联系方式。
下载示例:
https://gitee.com/xproer/up6-jsp-eclipse/tree/6.5.40/
工程
NOSQL
NOSQL示例不需要任何配置,可以直接访问测试
创建数据表
选择对应的数据表脚本,这里以SQL为例
修改数据库连接信息
访问页面进行测试
文件存储路径
up6/upload/年/月/日/guid/filename
相关问题:1.javax.servlet.http.HttpServlet错误2.项目无法发布到tomcat3.md5计算完毕后卡住4.服务器找不到config.json文件
相关参考:
文件保存位置
源码工程文档:https://drive.weixin.qq.com/s?k=ACoAYgezAAw1dWofra
源码报价单:https://drive.weixin.qq.com/s?k=ACoAYgezAAwoiul8gl
OEM版报价单:https://drive.weixin.qq.com/s?k=ACoAYgezAAwuzp4W0a
控件源码下载:https://drive.weixin.qq.com/s?k=ACoAYgezAAwbdKCskc
java实现大文件的分片上传与下载
java实现大文件的分片上传与下载,java实现大文件的分片上传与下载解决方案,java实现大文件的分片上传与下载思路,java实现大文件的分片上传与下载源码,java实现大文件的分片上传与下载实例,java实现大文件的分块上传与下载,java实现大文件的切片上传与下载,java实现大文件加密上传与下载,java实现大文件批量上传与下载,java实现文件夹上传与下载,
后端用的JAVA,JSP,SpringBoot,前端用了JSP,VUE2,VUE3,React,需要实现大文件的上传和下载。
要求支持大文件上传和下载,上传支持断点续传,下载支持断点续传,断点续传均支持刷新续传,关闭浏览器,重启浏览器,关闭电脑,重启电脑后仍然可以续传,支持大文件秒传。
提供前端,后端,控件源代码,提供长期技术支持,提供升级产品维护服务
需要支持包含IE在内的所有浏览器,需要支持信创国产化环境,比如银河麒麟,中标麒麟,龙芯,统信等,
需要支持加密传输,端到端的加密传输,支持国密SM4,上传过程加密,下载过程加密,客户单位涉密了。
文件上传页面的前端可以选择使用一些比较好用的上传组件,例如百度的开源组件WebUploader,泽优软件的up6,这些组件基本能满足文件上传的一些日常所需功能,如异步上传文件,文件夹,拖拽式上传,黏贴上传,上传进度监控,文件缩略图,甚至是大文件断点续传,大文件秒传。
在web项目中上传文件夹现在已经成为了一个主流的需求。在OA,或者企业ERP系统中都有类似的需求。上传文件夹并且保留层级结构能够对用户行成很好的引导,用户使用起来也更方便。能够提供更高级的应用支撑。
对于大文件的处理,无论是用户端还是服务端,如果一次性进行读取发送、接收都是不可取,很容易导致内存问题。所以对于大文件上传,采用切块分段上传
从上传的效率来看,利用多线程并发上传能够达到最大效率。
秒传功能,相信大家都体现过了,网盘上传的时候,发现上传的文件秒传了。其实原理稍微有研究过的同学应该知道,其实就是检验文件MD5,记录下上传到系统的文件的MD5,在一个文件上传前先获取文件内容MD5值或者部分取值MD5,然后在匹配系统上的数据。
导入项目:导入到Eclipse:http://www.ncmem.com/doc/view.aspx?id=9da9c7c2b91b40b7b09768eeb282e647导入到IDEA:http://www.ncmem.com/doc/view.aspx?id=9fee385dfc0742448b56679420f22162springboot统一配置:http://www.ncmem.com/doc/view.aspx?id=7768eec9284b48e3abe08f032f554ea2
下载示例:
https://gitee.com/xproer/up6-jsp-eclipse/tree/6.5.40/
工程
NOSQL
NOSQL示例不需要任何配置,可以直接访问测试
创建数据表
选择对应的数据表脚本,这里以SQL为例
修改数据库连接信息
访问页面进行测试
文件存储路径
up6/upload/年/月/日/guid/filename
相关问题:1.javax.servlet.http.HttpServlet错误2.项目无法发布到tomcat3.md5计算完毕后卡住4.服务器找不到config.json文件相关参考:
文件保存位置
源码工程文档:https://drive.weixin.qq.com/s?k=ACoAYgezAAw1dWofra
源码报价单:https://drive.weixin.qq.com/s?k=ACoAYgezAAwoiul8gl
OEM版报价单:https://drive.weixin.qq.com/s?k=ACoAYgezAAwuzp4W0a
产品源代码:https://drive.weixin.qq.com/s?k=ACoAYgezAAwbdKCskc授权生成器:https://drive.weixin.qq.com/s?k=ACoAYgezAAwTIcFph1
本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com
文章为作者独立观点不代本网立场,未经允许不得转载。