利用HTML5分片上传超大文件

转载 2015年11月20日 15:16:12

在网页中直接上传大文件一直是个比较头疼的问题,主要面临的问题一般包括两类:一是上传时间长中途一旦出错会导致前功尽弃;二是服务端配置复杂,要考虑接收超大表单和超时问题,如果是托管主机没准还改不了配置,默认只能接收小于4MB的附件。

比较理想的方案是能够把大文件分片,一片一片的传到服务端,再由服务端合并。这么做的好处在于一旦上传失败只是损失一个分片而已,不用整个文件重传,而且每个分片的大小可以控制在4MB以内,服务端不用做任何设置就可适应。

常用的解决方案是RIA,以flex为例,通常是利用FileReference.load方法加载文件得到ByteArray,然后分片构造表单(flash的高版本不允许直接访问文件)。不过这个load方法只能加载较小的文件,大约不超过300MB,因此适用性不是很强。

好在现在有了HTML5,我们可以直接构造分片了,这是一个非常喜人的进步,只可惜目前适用面不广(IE啊IE,真是恨你恨得牙痒痒)。

言归正传,来看一个DEMO吧,基于ASP.Net MVC3,只是示例,很多问题做了简化处理。

主要是客户端,新特性都体现在这里:

 


<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>

<!DOCTYPE html>

<html lang="zh-CN">

<head>

    <meta charset="utf-8">

    <title>HTML5大文件分片上传示例</title>

    <script src="../Scripts/jquery-1.11.1.min.js"></script>

    <script>

    var page = {

        init: function(){

            $("#upload").click($.proxy(this.upload, this));

        },

       

        upload: function(){

            var file = $("#file")[0].files[0],  //文件对象

                name = file.name,        //文件名

                size = file.size,        //总大小

                succeed = 0;

                 

            var shardSize = 2 * 1024 * 1024,    //以2MB为一个分片

                shardCount = Math.ceil(size / shardSize);  //总片数

                 

            for(var i = 0;i < shardCount;++i){

                //计算每一片的起始与结束位置

                var start = i * shardSize,

                    end = Math.min(size, start + shardSize);

 

                //构造一个表单,FormData是HTML5新增的

                var form = new FormData();

                form.append("data", file.slice(start,end));  //slice方法用于切出文件的一部分

                form.append("name", name);

                form.append("total", shardCount);  //总片数

                form.append("index", i + 1);        //当前是第几片

               

                //Ajax提交

                $.ajax({

                    url: "../File/Upload",

                    type: "POST",

                    data: form,

                    async: true,        //异步

                    processData: false,  //很重要,告诉jquery不要对form进行处理

                    contentType: false,  //很重要,指定为false才能形成正确的Content-Type

                    success: function(){

                        ++succeed;

                        $("#output").text(succeed + " / " + shardCount);

                    }

                });

            }

        }

    };

    $(function(){

        page.init();

    });

    </script>

</head>

<body>

    <input type="file" id="file" />

    <button id="upload">上传</button>

    <span id="output" style="font-size:12px">等待</span>

</body>

</html>

这里的slice方法和FormData都是html5之前不存在的。通过这样的方法,我们的表单构造出来是这样的,抓包看看:

利用HTML5分片上传超大文件

可以看到构造出来的Content-Type是multipart/form-data,也就是符合RFC标准的那个最传统的文件上传表单。另外我们同时传输的name、total等属性也都在表单里。

然后是服务端,没什么新鲜的,完全是在接收一个普通的文件:


[HttpPost]

public ActionResult Upload()

{

    //从Request中取参数,注意上传的文件在Requst.Files中

    string name = Request["name"];

    int total = Convert.ToInt32(Request["total"]);

    int index = Convert.ToInt32(Request["index"]);

    var data = Request.Files["data"];

   

    //保存一个分片到磁盘上

    string dir = Server.MapPath("~/Upload");

    string file = Path.Combine(dir, name + "_" + index);

    data.SaveAs(file);

   

    //如果已经是最后一个分片,组合

    //当然你也可以用其它方法比如接收每个分片时直接写到最终文件的相应位置上,但要控制好并发防止文件锁冲突

    if(index == total)

    {

        file = Path.Combine(dir, name);

        var fs = new FileStream(file, FileMode.Create);

        for(int i = 1;i <= total;++i)

        {

            string part = Path.Combine(dir, name + "_" + i);

            var bytes = System.IO.File.ReadAllBytes(part);

            fs.Write(bytes, 0, bytes.Length);

            bytes = null;

            System.IO.File.Delete(part);

        }

        fs.Close();

    }

   

    //返回是否成功,此处做了简化处理

    return Json(new { Error = 0 });

}

上面的DEMO很多问题是简化处理的,比如没做什么异常处理,客户端也没有判断服务端是否出错重试一类的,各位可以自己完善。

在上面的基础上,我们可以做很多功能上的扩展,比如我们可以控制所有分片是顺序上传还是并发上传,以适用不同应用。再比如我们可以在整体文件上传前以及分片上传前都先计算一下相应的HASH,发个请求询问服务器文件是否已存在,如果存在就不要重复上传了,这样就实现了“极速上传”以及“断点续传”。

 

HTML5 地理位置定位(HTML5 Geolocation)原理及应用 http://www.linuxidc.com/Linux/2012-07/65129.htm

HTML5移动开发即学即用(双色) PDF+源码 http://www.linuxidc.com/Linux/2013-09/90351.htm

HTML5入门学习笔记 http://www.linuxidc.com/Linux/2013-09/90089.htm

HTML5移动Web开发笔记 http://www.linuxidc.com/Linux/2013-09/90088.htm

HTML5 开发中的本地存储的安全风险 http://www.linuxidc.com/Linux/2013-06/86486.htm

《HTML5与CSS3权威指南》及相配套源码 http://www.linuxidc.com/Linux/2013-02/79950.htm

关于 HTML5 令人激动的 10 项预测 http://www.linuxidc.com/Linux/2013-02/79917.htm

HTML5与CSS3实战指南 PDF http://www.linuxidc.com/Linux/2013-02/79910.htm

原文链接为http://www.linuxidc.com/Linux/2014-09/106816.htm

相关文章推荐

html5大文件上传技术

html5大文件上传技术引言 普通html表单在上传几KB或几MB级别的文件基本无压力,但在上传上百MB甚至是GB级别大文件很无爱。而且一般服务器单个文件上传限制基本都在几MB之内。如何有有效突破...

利用HTML5分片上传超大文件

在网页中直接上传大文件一直是个比较头疼的问题,主要面临的问题一般包括两类:一是上传时间长中途一旦出错会导致前功尽弃;二是服务端配置复杂,要考虑接收超大表单和超时问题,如果是托管主机没准还改不了配置,默...

html5+Ajax上传超大型文件(文件切割技术)

在这里上传:文件大小 无限制,带进度条 ,带进度度联系到浏览器的渲染原理,这也是根据老师的步骤来的,没有老师的指导我也做不出来 Insert title here #result{ width...

利用HTML5分片上传超大文件

利用HTML5分片上传超大文件 在网页中直接上传大文件一直是个比较头疼的问题,主要面临的问题一般包括两类:一是上传时间长中途一旦出错会导致前功尽弃;二是服务端配置复杂,要考虑接收超大表单和超...

HTML5利用FormData对象实现显示进度条的文件上传【译】

这篇文章是我翻译的外文,非本人原创 网上看到很多博客都有转载这篇文章 不过转载的都是英文 所以我就决定翻译一下 (翻译和格式化也耗费了一番心血 (~﹃~)~zZ) 英文能力有限,大家凑合看吧...

利用HTML5+的Uploader模块API实现基于MUI的文件上传

版权声明:本文为博主原创文章,未经博主允许不得转载。 最近由于公司项目的需要,使用HBuilder开发基于MUI的web版APP,其中有一个文件上传的功能,通过查询资料,发现利用HTML5+的Uplo...

多文件拖拽上传以及利用Jquery替代HTML5上传控件

最近一直在研究文件上传的各种方法以及使用其他控件去重构HTML5自带的上传控件,这一篇将会总结这段时间研究的文件上传的两种方式,并对这一方面告一段落。本文将分为两部分介绍并解释文件上传的原理和实现过程...

使用APICloud编写优雅的HTML5代码《二》:ajax、文件上传

摘要: 对于ajax这个API而言,它实际上是有非常多的参数可供开发者选择的,以此满足各种特殊的需求,包括:url、method、cache、timeout、dataType、charset、head...

提升用户体验:HTML5 拖放文件上传

来源:http://sofish.de/1545 话说,还是有不少项目里提供让用户上传东西的。小到一个 wordpress 博客,大到一个文件存储网站。为了更好的用户体验。来学习两个新知识吧...

android webview 嵌入html5 定位 文件上传

android webview html5 上传文件 百度定位
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)