龙空技术网

JS分片上传大文件并显示进度条实例

逍遥总遥 708

前言:

此时你们对“js实现文件夹”都比较关注,你们都需要剖析一些“js实现文件夹”的相关文章。那么小编同时在网摘上收集了一些关于“js实现文件夹””的相关文章,希望你们能喜欢,小伙伴们快快来了解一下吧!

上篇文章说明了如何用js在客户端上传文件,功能是实现了,但当上传大文件时,一是时间长,像卡死了一样,二是用户不知道进度很容易在没上传完之前就关掉。今天我们就来看如何在客户端将大文件分片上传,并显示进度。

先来看一下效果:1、新建一个"js_upBigFile"的项目,添加一个webForm1.aspx,给WebForm1添加如下控件,这里进度条用一个就可以,我这里是演示如何用进度条控件progress和用div模拟两种方式显示。Form外面的基本信息这些,都是用来监控效果的控件,实际应用时是不需要的。

<body>    <form id="form1" runat="server">        <input type="file" id="f" />        <br />        <input type="button" value="up" onclick="up()" />        <br />        <!--进度条标签-->        <progress value="0" max="100" id="progress" style="height: 20px; width: 100%"></progress>        <br />        <!--div模拟进度条-->        <div id="progressNumber" style="width: 0%; height: 20px; background-color: Red"></div>        <br />        <div id="result"></div>    </form>    <p>        基本信息:<input id="Text1" type="text" /></p>    <p>        正在上传:<input id="Text2" type="text" /></p>    <p>        正在处理:<input id="Text3" type="text" /></p>    <p>        <textarea id="TextArea1" name="S1"></textarea></p>    <p>        <textarea id="TextArea2" name="S2" cols="20" rows="1"></textarea></p></body>
2、在项目目录下新建两个文件夹,一个“1”来存储临时文件,一个“2”来存储上传后的文件。注意不是“bin"目录。3、添加点击按钮的js代码

这个按钮就是点击执行js代码的按钮,<input type="button" value="up" onclick="up()" />

js函数up()的代码如下:

<script type="text/ecmascript">    //每个切片文件的大小 1024 * 1024 就是1M,下面我这里就是2M    var bytesPerPiece = 1024 * 1024 * 2;    var totalPieces;    pieceover = 0;    hbindex = 0;    totalPieces = 0;    function up() {        if (document.getElementById("f").value == "") {            document.getElementById("result").innerHTML = "请选择文件";        }        else {            var fileObj = document.getElementById("f").files[0];            var start = 0;            var end;            var index = 0;            var filesize = fileObj.size;            var filename = fileObj.name;            //获取最后一个.的位置            var exindex = filename.lastIndexOf(".");            //获取扩展名,带.            var fileexname = filename.substr(exindex);            //计算文件切片总数,也就是一共多少个文件            totalPieces = Math.ceil(filesize / bytesPerPiece);            infostr = "";            infostr += " 文件名:" + filename;            infostr += " 大小:" + filesize;            infostr += " 总数:" + totalPieces;            document.getElementById("Text1").value = infostr;            while (start < filesize) {                //分片结束大小位置                end = start + bytesPerPiece;                if (end > filesize) {                    end = filesize;                }                //建立xhr                var xhr = new XMLHttpRequest();                //对应的处理数据的 ashx 文件 -------------  注意这里                var url = "upFile.ashx";                //得到分片文件,根据开始位置和结束位置                var chunk = fileObj.slice(start, end);                var sliceIndex = fileObj.name + index;                //FormData对象                var fd = new FormData();                //文件素引,也就是当前是第几个片文件                fd.append("index", index);                    //将分片文件做为参数传到ashx文件中上传                fd.append("file", chunk, filename);                //加上当前的时间,据称可以防止文件缓存,我没有试过,反正写上吧                fd.append("time", new Date().toString());                xhr.open("POST", url, true);                xhr.onreadystatechange = function () {                    //全部上传完毕以后,弹出菜单                    if (xhr.readyState == 4 && xhr.status == 200) {                        alert("分片结束");                    }                }                                //上传结束后,注意这里是上传一个就会运行一次,                //也正是这种机制使我们可以监控上传进度                xhr.upload.onloadend = function (evt) {                    pieceover++;                    document.getElementById("Text2").value = pieceover;                                        var percentComplete = (pieceover / totalPieces * 100).toFixed(4);                    document.getElementById('progress').value = percentComplete;                    document.getElementById('progressNumber').style.width = percentComplete + "%";                    document.getElementById("result").innerHTML = "第1步(共2步):已经完成:" + percentComplete + "%";                }								//发送数据                xhr.send(fd);                                //更改下次分片文件的起始位置                start = end;                index++;            }        }    }</script>
4、添加一个upFile.ashx一般处理程序代码如下:
using System;using System.Web;namespace WebApplication1{    /// <summary>    /// upFile 的摘要说明    /// </summary>    public class upFile : IHttpHandler    {        public void ProcessRequest(HttpContext context)        {            //服务端存储分片文件的地址            string rootpath = System.Web.HttpContext.Current.Server.MapPath("~");            string savePath = rootpath + "\\1\\";            //得到分片文件的索引名            string index = context.Request["index"];            //得到传过来的分片文件            HttpPostedFile file = context.Request.Files[0];            //文件扩展名            string fileType = System.IO.Path.GetExtension(file.FileName);            //存到文件服务器的文件名称 用当前时间命名            //string fileNewName = DateTime.Now.ToString("yyyyMMddHHmmss_fff") + fileType;            string fileNewName = index + fileType;            try            {                //上传                file.SaveAs(savePath + fileNewName);                context.Response.Write("上传成功!");            }            catch (Exception ex)            {                context.Response.Write("上传失败!错误信息:" + ex.Message.ToString());            }        }        public bool IsReusable        {            get            {                return false;            }        }    }}
此时第一步分片上传已经结束,运行效果如下:

1文件夹中的内容

5、通过上面4步,我们就将文件分片上传到服务器上了,这就完成了第一步,现在我们做第二步,在服务器上把文件合并起来。

在js中新加几个变量

pieceover = 0; //已经合并的文件总数

hbindex = 0; //当前正在合并的索引号

totalPieces = 0; //总共要合并的文件总数

将up函数中结束的部分换成如下代码,再用go()函数开始合并

xhr.onreadystatechange = function () {                    //全部上传完毕以后,弹出菜单                    xhr.onreadystatechange = function () {                    if (xhr.readyState == 4 && xhr.status == 200) {                        if (pieceover == totalPieces) {  //如果还没有开始合并                            pieceover = 0;  //从第0片开始合并                            //重置滚动条                            document.getElementById('progress').value = 0;                            //开始合并                            go(0, filename, fileexname);                        }                    }                }
6、go函数代码:
function go(index, newfilename, exname) {        var xhr1 = new XMLHttpRequest();        var url1 = "HeBin.ashx";    //这次用一个新的处理文件        var fd1 = new FormData();        xhr1.open("POST", url1, true);        xhr1.onreadystatechange = function () {            if (xhr1.readyState == 4 && xhr1.status == 200) {                var result1 = xhr1.responseText;                if (result1 != "") {                    if (pieceover < totalPieces) {                        if (result1 == hbindex) {                            document.getElementById("TextArea2").value += "Y(result1:" + result1 + ",hbindex:" + hbindex + ")";                            pieceover++;                            document.getElementById("Text3").value = pieceover;                            //var percentComplete = Math.round(pieceover * 100 / totalPieces)                            var percentComplete = (pieceover / totalPieces * 100).toFixed(4);                            document.getElementById('progress').value = percentComplete;                            document.getElementById('progressNumber').style.width = percentComplete + "%";                            document.getElementById("result").innerHTML = "第2步(共2步):已经完成:" + percentComplete + "%";                            hbindex++;                            document.getElementById("TextArea1").value += hbindex;                            go(hbindex, newfilename, exname);                            document.getElementById("TextArea1").value += "over,result:" + result1;                        }                    }                    else {                        document.getElementById("result").innerHTML = "上传成功!";                    }                }                else                {                    if (pieceover >= totalPieces) {                        document.getElementById("result").innerHTML = "上传成功!";                    }                }            }        }                fd1 = new FormData();        fd1.append("newfilename", newfilename); //合并成的文件名        fd1.append("filename", hbindex);   //文件名(索引)        fd1.append("exname", exname);      //扩展名        fd1.append("acttime", new Date().toString());        xhr1.send(fd1);    }
7、再添加一个HeBin.ashx,用来把上传上去的分片文件合并,代码如下
using System;using System.IO;using System.Web;namespace WebApplication1{    /// <summary>    /// HeBin 的摘要说明    /// </summary>    public class HeBin : IHttpHandler    {        public void ProcessRequest(HttpContext context)        {            string NewFileName = context.Request["newfilename"];            //服务器路径            string rootpath = System.Web.HttpContext.Current.Server.MapPath("~");            //临时文件路径            string qiepianpath = rootpath  + "1\\";            //要处理的文件名,不带扩展名,如 0 1            string nowname = context.Request["filename"];            //扩展名            string fileType = context.Request["exname"];            //要处理的文件名,带扩展名,如 0.mp4            string nownameall = nowname + fileType;            //要处理的文件完整路径            string thepath = qiepianpath + nownameall;            //调试用,万一哪里出错了,可以根据这个数字看看到底是哪个文件错了            int time = 0;              try            {                string filename = NewFileName;                string SaveFileName = rootpath + "2\\" + filename;                using (FileStream fs = new FileStream(SaveFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))                {                    using (FileStream readStream = new FileStream(thepath, FileMode.Open, FileAccess.Read))                    {                        byte[] buffer = new byte[readStream.Length];                        int data = 0;                                                //合并文件                        while ((data = readStream.Read(buffer, 0, 1024)) > 0)                        {                            fs.Position = fs.Length;                            fs.Write(buffer, 0, data);                        }                    }                    fs.Dispose();                    File.Delete(thepath);                    context.Response.Write(nowname);                }            }            catch (Exception x)            {                time++;            }        }        public bool IsReusable        {            get            {                return false;            }        }    }}
运行程序,在合并时能明显看到文件正在被合并的效果到这整个程序部分就结束了。

需要说明的是:

//每个切片文件的大小 1024 * 1024 就是1M,下面我这里就是2M

var bytesPerPiece = 1024 * 1024 * 2;

这个分片文件不是越大越好,越大上传越慢,但也不是越小越好,我感觉分片文件的个数在不同硬盘上是有限制的,反正这个数最好是根据自己的情况多测试几遍。

标签: #js实现文件夹