利用Plupload.js解决大文件上传问题, 带进度条和背景遮罩层


Posted in Javascript onMarch 15, 2017

大容量文件上传早已不是什么新鲜问题,在.net 2.0时代,HTML5也还没有问世,要实现这样的功能,要么是改web.config,要么是用flash,要么是用一些第三方控件,然而这些解决问题的方法要么很麻烦,比如改配置,要么不稳定,比如文件上G以后,上传要么死掉,要么卡住,通过设置web.config并不能很好的解决这些问题。

这是一个Html5统治浏览器的时代,在这个新的时代,这种问题已被简化并解决,我们可以利用Html5分片上传的技术,那么Plupload则是一个对此技术进行封装的前端脚本库,这个库的好处是可以自动检测浏览器是否支持html5技术,不支持再检测是否支持flash技术,甚至是sliverlight技术,如果支持,就使用检测到的技术。

那么这个库到哪里下载,怎么搭建呢,比较懒的童鞋还是用Install-Package Plupload搞定吧,一个命令搞定所有事

下面给出一个例子,使用自已定义的控件来使用Plupload (Plupload也有自己的界面可以用),如下

利用Plupload.js解决大文件上传问题, 带进度条和背景遮罩层

Plupload支持的功能这里就不细说了,什么批量上传,这里我没有用到,主要是感觉它支持的事件非常丰富,文件选取后的事件,文件上传中的事件(可获得文件的上传进度),文件上传成功的事件,文件上传失败的事件,等等

我的例子主要是上传一个单个文件,并显示上传的进度条(使用jQuery的一个进度条插件)

下面的例子主要是为文件上传交给 UploadCoursePackage.ashx 来处理

/******************************************************ProgressBar********************************************************/
      var progressBar = $("#loading").progressbar({ width: '500px', color: '#B3240E', border: '1px solid #000000' });
      /******************************************************Plupload***********************************************************/
      //实例化一个plupload上传对象
      var uploader = new plupload.Uploader({
        browse_button: 'browse', //触发文件选择对话框的按钮,为那个元素id
        runtimes: 'html5,flash,silverlight,html4',//兼容的上传方式
        url: "Handlers/UploadCoursePackage.ashx", //后端交互处理地址
        max_retries: 3,   //允许重试次数
        chunk_size: '10mb', //分块大小
        rename: true, //重命名
        dragdrop: false, //允许拖拽文件进行上传
        unique_names: true, //文件名称唯一性

        filters: { //过滤器
          max_file_size: '999999999mb', //文件最大尺寸
          mime_types: [ //允许上传的文件类型
            { title: "Zip", extensions: "zip" },
            { title: "PE", extensions: "pe" }
          ]
        },
        //自定义参数 (键值对形式) 此处可以定义参数
        multipart_params: {
          type: "misoft"
        },
        // FLASH的配置
        flash_swf_url: "../Scripts/plupload/Moxie.swf",

        // Silverligh的配置
        silverlight_xap_url: "../Scripts/plupload/Moxie.xap",

        multi_selection: false //true:ctrl多文件上传, false 单文件上传 
      });

      //在实例对象上调用init()方法进行初始化
      uploader.init();

      uploader.bind('FilesAdded', function (uploader, files) {
        $("#<%=fileSource.ClientID %>").val(files[0].name);
        $.ajax(
        {
          type: 'post',
          url: 'HardDiskSpace.aspx/GetHardDiskFreeSpace',
          data: {},
          dataType: 'json',
          contentType: 'application/json;charset=utf-8',
          success: function (result) {
            //选择文件以后检测服务器剩余磁盘空间是否够用
            if (files.length > 0) {
              if (parseInt(files[0].size) > parseInt(result.d)) {
                $('#error-msg').text("文件容量大于剩余磁盘空间,请联系管理员!");
              } else {
                $('#error-msg').text("");
              }
            }
          },
          error: function(xhr, err, obj) {
            $('#error-msg').text("检测服务器剩余磁盘空间失败");
          }
        });
      });

      uploader.bind('UploadProgress', function (uploader, file) {
        var percent = file.percent;
        progressBar.progress(percent);
      });

      uploader.bind('FileUploaded', function (up, file, callBack) {
        var data = $.parseJSON(callBack.response);
        if (data.statusCode === "1") {
          $("#<%=hfPackagePath.ClientID %>").val(data.filePath);
          var id = $("#<%=hfCourseID.ClientID %>").val();
          __doPostBack("save", id);
        } else {
          hideLoading();
          $('#error-msg').text(data.message);
        }
      });

      uploader.bind('Error', function (up, err) {
        alert("文件上传失败,错误信息: " + err.message);
      });

后台 UploadCoursePackage.ashx 的代码也重要,主要是文件分片跟不分片的处理方式不一样

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;

namespace WebUI.Handlers
{
  /// <summary>
  /// UploadCoursePackage 的摘要说明
  /// </summary>
  public class UploadCoursePackage : IHttpHandler
  {

    public void ProcessRequest(HttpContext context)
    {
      context.Response.ContentType = "text/plain";

      int statuscode = 1;
      string message = string.Empty;
      string filepath = string.Empty;

      if (context.Request.Files.Count > 0)
      {
        try
        {
          string resourceDirectoryName = System.Configuration.ConfigurationManager.AppSettings["resourceDirectory"];
          string path = context.Server.MapPath("~/" + resourceDirectoryName);
          if (!Directory.Exists(path))
            Directory.CreateDirectory(path);

          int chunk = context.Request.Params["chunk"] != null ? int.Parse(context.Request.Params["chunk"]) : 0; //获取当前的块ID,如果不是分块上传的。chunk则为0
          string fileName = context.Request.Params["name"]; //这里写的比较潦草。判断文件名是否为空。
          string type = context.Request.Params["type"]; //在前面JS中不是定义了自定义参数multipart_params的值么。其中有个值是type:"misoft",此处就可以获取到这个值了。获取到的type="misoft";

          string ext = Path.GetExtension(fileName);
          //fileName = string.Format("{0}{1}", Guid.NewGuid().ToString(), ext);
          filepath = resourceDirectoryName + "/" + fileName;
          fileName = Path.Combine(path, fileName);

          //对文件流进行存储 需要注意的是 files目录必须存在(此处可以做个判断) 根据上面的chunk来判断是块上传还是普通上传 上传方式不一样 ,导致的保存方式也会不一样
          FileStream fs = new FileStream(fileName, chunk == 0 ? FileMode.OpenOrCreate : FileMode.Append);
          //write our input stream to a buffer
          Byte[] buffer = null;
          if (context.Request.ContentType == "application/octet-stream" && context.Request.ContentLength > 0)
          {
            buffer = new Byte[context.Request.InputStream.Length];
            context.Request.InputStream.Read(buffer, 0, buffer.Length);
          }
          else if (context.Request.ContentType.Contains("multipart/form-data") && context.Request.Files.Count > 0 && context.Request.Files[0].ContentLength > 0)
          {
            buffer = new Byte[context.Request.Files[0].InputStream.Length];
            context.Request.Files[0].InputStream.Read(buffer, 0, buffer.Length);
          }

          //write the buffer to a file.
          if (buffer != null)
            fs.Write(buffer, 0, buffer.Length);
          fs.Close();

          statuscode = 1;
          message = "上传成功";

        }
        catch (Exception ex)
        {
          statuscode = -1001;
          message = "保存时发生错误,请确保文件有效且格式正确";

          Util.LogHelper logger = new Util.LogHelper();
          string path = context.Server.MapPath("~/Logs");
          logger.WriteLog(ex.Message, path);
        }
      }
      else
      {
        statuscode = -404;
        message = "上传失败,未接收到资源文件";
      }

      string msg = "{\"statusCode\":\"" + statuscode + "\",\"message\":\"" + message + "\",\"filePath\":\"" + filepath + "\"}";
      context.Response.Write(msg);
    }

    public bool IsReusable
    {
      get
      {
        return false;
      }
    }
  }
}

再附送一个检测服务器端硬盘剩余空间的功能吧

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Script.Services;
using System.Web.Services;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebUI
{
  public partial class CheckHardDiskFreeSpace : System.Web.UI.Page
  {
    protected void Page_Load(object sender, EventArgs e)
    {

    }

    /// <summary>
    /// 获取磁盘剩余容量
    /// </summary>
    /// <returns></returns>
    [WebMethod]
    public static string GetHardDiskFreeSpace()
    {
      const string strHardDiskName = @"F:\";

      var freeSpace = string.Empty;
      var drives = DriveInfo.GetDrives();
      var myDrive = (from drive in drives
        where drive.Name == strHardDiskName
        select drive).FirstOrDefault();
      if (myDrive != null)
      {
        freeSpace = myDrive.TotalFreeSpace+""; 
      }
      return freeSpace;
    }
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Javascript 中的 &amp;&amp; 和 || 使用小结
Apr 25 Javascript
jQuery $.each遍历对象、数组用法实例
Apr 16 Javascript
Jq通过td获取同行其它列td的方法
Oct 05 Javascript
浅析使用BootStrap TreeView插件实现灵活配置快递模板
Nov 28 Javascript
JS生成和下载二维码的代码
Dec 07 Javascript
javascript构造函数以及原型对象的理解
Jan 13 Javascript
ES6使用let命令更简单的实现块级作用域实例分析
Mar 31 Javascript
vue基于Vue2.0和高德地图的地图组件实例
Apr 28 Javascript
axios post提交formdata的实例
Mar 16 Javascript
vue移动端html5页面根据屏幕适配的四种解决方法
Oct 19 Javascript
在Create React App中使用CSS Modules的方法示例
Jan 15 Javascript
基于JavaScript实现表格隔行换色
May 08 Javascript
javascript九宫格图片随机打乱位置的实现方法
Mar 15 #Javascript
JavaScript实现审核流程状态的动态显示进度条
Mar 15 #Javascript
js实现自定义进度条效果
Mar 15 #Javascript
yii form 表单提交之前JS在提交按钮的验证方法
Mar 15 #Javascript
jQuery模拟窗口抖动效果
Mar 15 #Javascript
利用jQuery实现一个简单的表格上下翻页效果
Mar 14 #Javascript
基于React实现表单数据的添加和删除详解
Mar 14 #Javascript
You might like
老照片 - 几十年前的收音机与人
2021/03/02 无线电
通过对php一些服务器端特性的配置加强php的安全
2006/10/09 PHP
php字符串分割函数explode的实例代码
2013/02/07 PHP
PHP获取一年有几周以及每周开始日期和结束日期
2015/08/06 PHP
PHP中对数组的一些常用的增、删、插操作函数总结
2015/11/27 PHP
PHP实现webshell扫描文件木马的方法
2017/07/31 PHP
php+redis消息队列实现抢购功能
2018/02/08 PHP
javascript基本语法分析说明
2008/06/15 Javascript
jquery中ajax调用json数据的使用说明
2011/03/17 Javascript
js调用iframe实现打印页面内容的方法
2014/03/04 Javascript
百度移动版的url编码解码示例
2014/04/29 Javascript
JQuery给元素绑定click事件多次执行的解决方法
2014/05/29 Javascript
用js传递value默认值的示例代码
2014/09/11 Javascript
如何实现移动端浏览器不显示 pc 端的广告
2015/10/15 Javascript
javascript实现下拉提示选择框
2015/12/29 Javascript
jquery 实现滚动条下拉时无限加载的简单实例
2016/06/01 Javascript
Bootstrap警告(Alerts)的实现方法
2017/03/22 Javascript
JS伪继承prototype实现方法示例
2018/06/20 Javascript
nodejs图片处理工具gm用法小结
2018/12/12 NodeJs
vue 中 beforeRouteEnter 死循环的问题
2019/04/23 Javascript
解决elementUI 切换tab后 el_table 固定列下方多了一条线问题
2020/07/19 Javascript
[01:39:42]Fnatic vs Mineski 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/18 DOTA
Python RuntimeError: thread.__init__() not called解决方法
2015/04/28 Python
关于python pyqt5安装失败问题的解决方法
2017/08/08 Python
详解用Python实现自动化监控远程服务器
2019/05/18 Python
Python 实现自动完成A4标签排版打印功能
2020/04/09 Python
python不到50行代码完成了多张excel合并的实现示例
2020/05/28 Python
意大利包包和行李箱销售网站:Bagaglio.it
2021/03/02 全球购物
金融专业推荐信
2013/11/14 职场文书
大专应届生个人的自我评价
2013/11/21 职场文书
教师年度考核自我鉴定
2014/01/19 职场文书
《值日生》教学反思
2014/02/17 职场文书
投标承诺书怎么写
2014/05/24 职场文书
小学社团活动总结
2014/06/27 职场文书
《草船借箭》教学反思
2016/02/23 职场文书
详解Node.js如何处理ES6模块
2021/05/15 Javascript