利用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 API解决大文件上传问题

介绍了html5 File Api,实现分片上传大文件的方法。

html5解决大文件断点续传

js代码 xhr2 将图片拖拽到此 0% ajax上传--> 上传 //拖拽上传开始 //-1.禁止浏览...
  • Zph1234
  • Zph1234
  • 2016年01月25日 10:29
  • 5008

利用HTML5分片上传超大文件

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

使用Html5的WebSocket在浏览器上传文件, 支持多文件和大文件.

使用Html5的WebSocket在浏览器上传文件, 支持多文件和大文件. 使用websocket上传文件的简单例子: 使用Html5的WebSocket在浏览器上传文件 上篇文章...

上传大文件 NSInputStream

/** * @method + (NSString *)uploadVideoFilePath:(NSString *)filePath withFileName:(NSString *)file...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

大文件分片断点上传显示进度条

项目里面刚做完文件这块,本人负责文件分片上传功能模块,现将实现思路以及关键实现点整理一下。  文件分片断点上传思路如下: 第一步:分片上传 首先在本地沙盒Cache目录下创建一个专门存放上传文件的...

html5解决大文件断点续传

js代码 [html] view plain copy >  html>      head>          meta charset="UTF-8"/>      ...

利用HTML5分片上传超大文件

利用HTML5分片上传超大文件 在网页中直接上传大文件一直是个比较头疼的问题,主要面临的问题一般包括两类:一是上传时间长中途一旦出错会导致前功尽弃;二是服务端配置复杂,要考虑接收超大表单和超...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:利用HTML5分片上传超大文件
举报原因:
原因补充:

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