Web大文件断点续传

Web大文件断点续传,快来看看吧!

标签:php 上传

 

示例下载

asp.nethttp://www.ncmem.com/download/up6.3/asp.net/up6.3.rar

jsp-oraclehttp://www.ncmem.com/download/up6.3/jsp/Uploader6.3Oracle.rar

jsp-mysqlhttp://www.ncmem.com/download/up6.3/jsp/Uploader6.3MySQL.rar

jsp-sqlhttp://www.ncmem.com/download/up6.3/jsp/Uploader6.3SQL.rar

php-mysqlhttp://www.ncmem.com/download/up6.3/php/up6.3.rar

 

相信很多像我一样的好学的工程师对web的大文件的断点续传都有点儿兴趣,那么今天我们一起来动手实现它.

作为开始,我们先简单了解一下为什么要做断点续传:

 

传统方式的缺点

大文件上传往往比较耗时,如果采用传统的方式,势必速度慢,用户体验差.

大文件上传过程中,由于种种原因,时常导致上传中断,失败.用户已经成功上传的部分将需要再次重新上传.

上传大文件时,将导致页面卡顿,体验差

不能充分发挥系统的性能.主要是单线程.

断点续传将解决以上问题.

接下来我们了解一下在web中实现大文件上传的断点续传的原理.

 

基本原理

断点续传可以分为两部分:断点和续传。断点是在上传过程中,将一个将要上传的文件分成了多个部分,然后使用多个并发线程进行多个部分的上传当某个时间点,由于某种原因任务被暂停了此时上传暂停的位置就是断点了。此时已经成功上传的部分将会被服务器保存续传就是当用户再次继续上传之前未完成的文件时系统不会重新上传之前已经成功上传的部分,而是直接从之前暂停的部分开始上传.

 

断点续传的过程:

在准备上传文件之前,先将大文件分成相同大小的文件块并编号.

然后开启多个线程同时上传多个文件块到服务器.

在发送每个文件块之前,先向服务器查询,该文件块是否已经上传过

如果该文件块已经成功上传,则跳过该文件块的上传.

如果该文件块未上传或者未完全上传,则上传该文件块.

当客户端上传完所有的文件块之后,通知服务器端合并所有的文件块

在了解了基本原理之后我们使用使用javaweb来实现它.

 

提前准备:

up6---- 提供断点续传的前端技术.

jquery----javascript脚本依赖于它

Commons-fileupload----提供文件上传的后端技术

Commons-io----Commons-fileupload依赖于它

说明:以上的文件可在文章开始部分下载

 

实现:

导入相关文件:

文字版

    <link href="js/up6.css" type="text/css" rel="Stylesheet"/>

    <script type="text/javascript" src="js/jquery-1.4.min.js"></script>

    <script type="text/javascript" src="js/json2.min.js" charset="utf-8"></script>

    <script type="text/javascript" src="js/up6.config.js" charset="utf-8" ></script>

    <script type="text/javascript" src="js/up6.app.js" charset="utf-8"></script>

     <script type="text/javascript" src="js/up6.edge.js" charset="utf-8"></script>

    <script type="text/javascript" src="js/up6.file.js" charset="utf-8" ></script>

    <script type="text/javascript" src="js/up6.folder.js" charset="utf-8" ></script>   

    <script type="text/javascript" src="js/up6.js" charset="utf-8" ></script>   

 

JS代码:

文字版:

<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.addFdError = function (jv) { alert("本地路径不存在:" + jv.path); };

    //设置附加字段信息

    cbMgr.Config.Fields["test"] = "test";

 

    $(document).ready(function()

    {

        //console.log(navigator.userAgent);

        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>

 

服务端代码:

f_create.jsp

文字版

<%@ page language="java" import="up6.*" pageEncoding="UTF-8"%><%@

page contentType="text/html;charset=UTF-8"%><%@   

     page import="com.google.gson.Gson" %><%@

     page import="up6.*" %><%@

     page import="up6.model.*" %><%@

     page import="up6.biz.*" %><%@   

     page import="org.apache.commons.lang.StringUtils" %><%@

     page import="java.net.URLDecoder" %><%@

     page import="java.net.URLEncoder" %><%

 

String id     = request.getParameter("id");

String md5         = request.getParameter("md5");

String uid         = request.getParameter("uid");

String lenLoc      = request.getParameter("lenLoc");//数字化的文件大小。12021

String sizeLoc     = request.getParameter("sizeLoc");//格式化的文件大小。10MB

String callback = request.getParameter("callback");

String pathLoc     = request.getParameter("pathLoc");

pathLoc            = PathTool.url_decode(pathLoc);

 

//参数为空

if ( StringUtils.isBlank(md5)

     && StringUtils.isBlank(uid)

     && StringUtils.isBlank(sizeLoc))

{

     out.write(callback + "({\"value\":null})");

     return;

}

 

FileInf fileSvr= new FileInf();

fileSvr.id = id;

fileSvr.uid = Integer.parseInt(uid);

fileSvr.nameLoc = PathTool.getName(pathLoc);

fileSvr.pathLoc = pathLoc;

fileSvr.lenLoc = Long.parseLong(lenLoc);

fileSvr.sizeLoc = sizeLoc;

fileSvr.deleted = false;

fileSvr.md5 = md5;

fileSvr.nameSvr = md5 + "." + PathTool.getExtention(fileSvr.nameLoc);

 

//所有单个文件均以md5方式存储

PathBuilderMd5 pb = new PathBuilderMd5();

fileSvr.pathSvr = pb.genFile(fileSvr.uid,fileSvr);

fileSvr.pathSvr = fileSvr.pathSvr.replace("\\","/");

 

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);     

}

 

Gson gson = new Gson();

String json = gson.toJson(fileSvr);

 

json = URLEncoder.encode(json,"UTF-8");//编码,防止中文乱码

json = json.replace("+","%20");

json = callback + "({\"value\":\"" + json + "\"})";//返回jsonp格式数据。

out.write(json);%>

 

f_post.jsp

文字版

<%@ page language="java" import="up6.DBFile" pageEncoding="UTF-8"%><%@

     page contentType="text/html;charset=UTF-8"%><%@

     page import="up6.FileBlockWriter" %><%@

     page import="up6.XDebug" %><%@

     page import="up6.*" %><%@

     page import="org.apache.commons.fileupload.FileItem" %><%@

     page import="org.apache.commons.fileupload.FileItemFactory" %><%@

     page import="org.apache.commons.fileupload.FileUploadException" %><%@

     page import="org.apache.commons.fileupload.disk.DiskFileItemFactory" %><%@

     page import="org.apache.commons.fileupload.servlet.ServletFileUpload" %><%@

     page import="org.apache.commons.lang.StringUtils" %><%@

     page import="java.net.URLDecoder"%><%@

     page import="java.util.Iterator"%><%@

     page import="java.util.List"%><%/*

     此页面负责将文件块数据写入文件中。

*/

 

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");

}%>

 

f_process.jsp

文字版

<%@ page language="java" import="up6.DBFile" pageEncoding="UTF-8"%><%@

     page contentType="text/html;charset=UTF-8"%><%@

     page import="org.apache.commons.lang.StringUtils" %><%

 

/*

     更新文件进度或文件夹进度,百分比

*/

 

String id              = request.getParameter("id");

String uid             = request.getParameter("uid");

String offset          = request.getParameter("offset");

String lenSvr          = request.getParameter("lenSvr");

String perSvr          = request.getParameter("perSvr");

String callback         = request.getParameter("callback");

int ret = 0;

 

if ( !StringUtils.isBlank(id)

     &&   !StringUtils.isBlank(lenSvr)

     &&   !StringUtils.isBlank(perSvr))

     {

         DBFile db = new DBFile();

         db.f_process(Integer.parseInt(uid),id,Long.parseLong(offset),Long.parseLong(lenSvr),perSvr);

         ret = 1;

     }

%><%=callback + "({\"value\":"+ret+"})"%>

 

f_complete.jsp

文字版

<%@ page language="java" import="up6.*" pageEncoding="UTF-8"%><%@

     page contentType="text/html;charset=UTF-8"%><%@

     page import="org.apache.commons.lang.StringUtils" %><%

/*

     此页面主要用来向数据库添加一条记录。

*/

 

String md5         = request.getParameter("md5");

String uid         = request.getParameter("uid");

String id          = request.getParameter("id");

String callback    = request.getParameter("callback");//jsonp

 

//返回值。1表示成功

int ret = 0;

if ( !StringUtils.isBlank(uid)

     && !StringUtils.isBlank(id)

     && !StringUtils.isBlank(md5))

{

     DBFile db = new DBFile();

     db.UploadComplete(md5);

     ret = 1;

}

%><%=callback + "(" + ret + ")"%>

 

f_list.jsp

文字版

<%@ page language="java" import="up6.*" pageEncoding="UTF-8"%><%@

     page contentType="text/html;charset=UTF-8"%><%@

     page import="up6.biz.*" %><%@

     page import="org.apache.commons.lang.StringUtils" %><%@

     page import="java.net.URLEncoder" %><%

/*

     获取所有未上传完的文件和文件夹

*/

String uid = request.getParameter("uid");

String cbk = request.getParameter("callback");//jsonp

 

if( uid.length() > 0 )

{

     String json = DBFile.GetAllUnComplete( Integer.parseInt( uid ) );

     if( !StringUtils.isBlank(json))

     {

         json = URLEncoder.encode(json,"utf-8");

         json = json.replace("+","%20");     

         out.write( cbk + "({\"value\":\""+json + "\"})" );

         return

     }

}

out.write(cbk + "({\"value\":null})");

%>

 

f_del.jsp

文字版

<%@ page language="java" import="up6.DBFile" pageEncoding="UTF-8"%><%@

     page contentType="text/html;charset=UTF-8"%><%@

     page import="org.apache.commons.lang.StringUtils" %><%

/*

     此页面主要用来向数据库添加一条记录。

     一般在 HttpUploader.js HttpUploader_MD5_Complete(obj) 中调用

     更新记录:

         2012-05-24 完善

         2012-06-29 增加创建文件逻辑,

*/

String path = request.getContextPath();

String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";

 

String fid = request.getParameter("id");

String uid = request.getParameter("uid");

String callback = request.getParameter("callback");//jsonp

int ret = 0;

 

if ( !StringUtils.isBlank(fid)

     &&   !StringUtils.isBlank(uid))

{

     DBFile db = new DBFile();

     db.Delete(Integer.parseInt(uid),fid);

     ret = 1;

}

%><%= callback + "(" + ret + ")" %>

 

END...

如果您看到了这里,那么希望您留下您对文章的任何见解看法.

 

 

 

猜你喜欢

转载自blog.csdn.net/activexme/article/details/79149873