目录
背景介绍
项目介绍
使用说明
获取代码
需要知识点
启动项目
项目示范
核心讲解
重要原理
功能分析
分块上传
秒传功能
断点续传
总结
背景介绍
up6。这是一个大文件上传的产品。该项目是基于荆门泽优的上传控件:HttpUploader6。它支持大文件上传(1G~20G+)和文件夹上传。是目前国内上传产品中做的最好的,无论是代码质量还是开发文档都是我见过的同领域中最好的。强烈推荐企业和公司使用。真的能够为企业节省不少人力成本,也为开发人员节省少少时间。
项目介绍
up6是一个基于大文件上传,并参考网盘上传文件,而基于web的大文件上传实现项目。web中上传大文件没有桌面软件那么容易,还好现在是身处于一个html5的时代。我们web端上传文件常用的做法就是用表单上传了,一旦上传的文件大小较大,一旦带宽跟不上,那用户只能在哪里一直等着,不能做刷新页面的操作,并且一旦产生网络波动,那么用户所做的一切就白费了。
up6就是为了保证在web端上传大文件能达到基本的可靠性的一种方案,方法多种,可能的方案会更出色,欢迎讨论。要让大文件上传能达到可用性,我们需要做到怎么样的程度呢?
* 断点续传 最主要的功能之一,在断网或者在暂停的情况下,能够在上传断点中继续上传。
* 文件夹上传 最主要的功能之一,能够直接上传整个文件夹,且自动处理层级关系,能够直接保存在数据库中,且支持文件夹MD5验证,文件夹秒传。
* 分块上传 也是断点续传的基础之一,把大文件通过前端分块,然后后台在组在一起。
* 文件秒传 能够自动检测重复文件,帮助服务器节省存储空间,帮助用户节省上传时间。
* 其他功能 把下面这些功能归类到其他,是因为它们基本都是通过up6(http://www.ncmem.com/v2/webapp/up6/index.aspx)来实现的,很简单。
- 多线程上传 多个线程上传不同的块文件。
- 文件进度显示 显示文件的上传完成情况。
- 自定义事件 能够根据项目需求增加或修改事件
- 可扩展性 能够根据项目需求增加或修改业务参数
使用说明
获取代码
在线代码(GitHub):asp.net,jsp-oracle,jsp-mysql,jsp-sql,php-mysql
在线代码(coding):asp.net,jsp-oracle,jsp-mysql,jsp-sql,php-mysql
在线代码(oschina):asp.net,jsp-oracle,jsp-mysql,jsp-sql,php-mysql
在线代码(csdn):asp.net,jsp-oracle,jsp-mysql,jsp-sql,php-mysql
持续更新。
需要知识点
基于jquery+html开发的。
启动项目
本地测试
jsp-mysql:http://bbs.ncmem.com/thread-291-1-1.html
jsp-oracle:http://bbs.ncmem.com/thread-192-1-1.html
jsp-sql:http://bbs.ncmem.com/thread-222-1-1.html
php-windows:http://bbs.ncmem.com/thread-112-1-1.html
php-linux:http://bbs.ncmem.com/thread-298-1-1.html
asp.net:http://bbs.ncmem.com/thread-193-1-1.html
项目示范
1.文件扫描界面
2.秒传界面
3.文件夹上传
核心讲解
核心原理
该项目核心就是文件分块上传。前后端要高度配合,需要双方约定好一些数据,才能完成大文件分块,我们在项目中要重点解决的以下问题。
* 如何分片;
* 如何合成一个文件;
* 中断了从哪个分片开始。
如何分,利用强大的js库,来减轻我们的工作,市场上已经能有关于大文件分块的轮子,虽然程序员的天性曾迫使我重新造轮子。但是因为时间的关系还有工作的关系,我只能罢休了。最后我选择了荆门泽优的HttpUploader6来实现前端所需。
功能分析
分块上传
分块上传可以说是我们整个项目的基础,像断点续传、暂停这些都是需要用到分块。
分块这块相对来说比较简单。前端是采用了up6,分块等基础功能已经封装起来,使用方便。
借助up6提供给我们的文件API,前端就显得异常简单。
<script language="javascript" type="text/javascript">
var cbMgr = new HttpUploaderMgr();
cbMgr.event.md5Complete = function (obj, md5) { /*alert(md5);*/ };
cbMgr.event.fileComplete = function (obj) { /*alert(obj.pathSvr);*/ };
cbMgr.event.queueComplete = function () { /*队列上传完毕*/ };
cbMgr.event.addFdError = function (jv) { alert("本地路径不存在:" + jv.path); };
$(function()
{
cbMgr.load_to("FilePanel");
//上传指定文件
$("#btnUpF").click(function () {
var path = $("#filePath").val();
cbMgr.app.addFile({ pathLoc: path });
});
//上传指定目录
$("#btnUpFd").click(function () {
var path = $("#folderPath").val();
cbMgr.app.addFolder({ pathLoc: path });
});
});
</script>
文件合并也非常简单,up6默认是将多个分块数据写入到一个文件中,所以这块不需要开发人员再手动合并了。
String uid = request.getHeader("uid");//
String id = request.getHeader("id");
String md5 = request.getHeader("md5");
String lenSvr = request.getHeader("lenSvr");
String lenLoc = request.getHeader("lenLoc");
String blockOffset = request.getHeader("blockOffset");
String blockSize = request.getHeader("blockSize");
String blockIndex = request.getHeader("blockIndex");
String complete = request.getHeader("complete");
String pathSvr = request.getHeader("pathSvr");
pathSvr = PathTool.url_decode(pathSvr);
//参数为空
if( StringUtils.isBlank( uid )
|| StringUtils.isBlank( id )
|| StringUtils.isBlank( blockOffset )
|| StringUtils.isBlank(pathSvr))
{
XDebug.Output("param is null");
return;
}
// Check that we have a file upload request
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List files = null;
try
{
files = upload.parseRequest(request);
}
catch (FileUploadException e)
{// 解析文件数据错误
out.println("read file data error:" + e.toString());
return;
}
FileItem rangeFile = null;
// 得到所有上传的文件
Iterator fileItr = files.iterator();
// 循环处理所有文件
while (fileItr.hasNext())
{
// 得到当前文件
rangeFile = (FileItem) fileItr.next();
}
//文件块验证
if(Integer.parseInt(blockSize) == rangeFile.getSize())
{
//保存文件块数据
FileBlockWriter res = new FileBlockWriter();
res.write( Long.parseLong(blockOffset),pathSvr,rangeFile);
rangeFile.delete();
out.write("ok");
}
else
{
rangeFile.delete();
out.write("block size error");
}
秒传功能
秒传功能,相信大家都体现过了,网盘上传的时候,发现上传的文件秒传了。其实原理稍微有研究过的同学应该知道,其实就是检验文件MD5,记录下上传到系统的文件的MD5,在一个文件上传前先获取文件内容MD5值或者部分取值MD5,然后在匹配系统上的数据。
up6实现秒传原理,用户选择文件后控件将会自动开启扫描线程开始计算文件MD5,扫描完毕后将会触发一个事件通知UI层,UI向服务器发送ajax请求查询数据库中是否已经存在相同MD5
DBFile db = new DBFile();
FileInf fileExist = new FileInf();
boolean exist = db.exist_file(md5,fileExist);
//数据库已存在相同文件,且有上传进度,则直接使用此信息
if(exist && fileExist.lenSvr > 1)
{
fileSvr.pathSvr = fileExist.pathSvr;
fileSvr.perSvr = fileExist.perSvr;
fileSvr.lenSvr = fileExist.lenSvr;
fileSvr.complete = fileExist.complete;
db.Add(fileSvr);
}//此文件不存在
else
{
db.Add(fileSvr);
FileBlockWriter fr = new FileBlockWriter();
fr.CreateFile(fileSvr.pathSvr);
}
断点续传
断点续传,就是在文件上传的过程中发生了中断,人为因素(暂停)或者不可抗力(断网或者网络差)导致了文件上传到一半失败了。然后在环境恢复的时候,重新上传该文件,而不至于是从新开始上传的。
前面也已经讲过,断点续传的功能是基于分块上传来实现的,把一个大文件分成很多个小块,服务端能够把每个上传成功的分块都落地下来,客户端在上传文件开始时调用接口快速验证,条件选择跳过某个分块。
up6在断点续传这块做的已经非常完善了,完全不需要开发人员再进行多余的操作。全自动化的处理。服务器也不需要额外处理,DEMO中就已经处理好了。
总结
up6无论是用来传文件还是用来传文件夹都是非常方便的,这为企业节省了相当多的时间成本和人力成本。对于开发人员来讲,up6有相当良好的接口设计,及参数扩展框架。可以非常方便的集成到其它的web系统中。
由于时间有限,所以就在这里大概介绍一些基础的东西,如果各位朋友想了解更具体的建议下载DEMO体验一下,谢谢大家。
参考文献
[1]http://www.ncmem.com/doc/up6/index.aspx
[2]http://www.cnblogs.com/xproer/category/355072.html
[3]http://www.cnblogs.com/xproer/archive/2012/02/17/2355469.html