利用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 DOM事件模型的两件事
Jul 22 Javascript
jQuery UI Autocomplete 1.8.16 中文输入修正代码
Apr 16 Javascript
jQuery 数据缓存模块进化史详细介绍
Nov 19 Javascript
JavaScript DOM元素尺寸和位置
Apr 13 Javascript
BootStrap下jQuery自动完成的样式调整
May 30 Javascript
jquery实现的回旋滚动效果完整实例【附demo源码下载】
Sep 20 Javascript
Jquery-data的三种用法
Apr 18 jQuery
node.js利用mongoose获取mongodb数据的格式化问题详解
Oct 06 Javascript
JS实现延迟隐藏功能的方法(类似QQ头像鼠标放上展示信息)
Dec 28 Javascript
JavaScript变量声明var,let.const及区别浅析
Apr 23 Javascript
详解在Vue.js编写更好的v-for循环的6种技巧
Apr 14 Javascript
前端如何实现动画过渡效果
Feb 05 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
基于mysql的bbs设计(五)
2006/10/09 PHP
深入PHP curl参数的详解
2013/06/17 PHP
PHP获取一年有几周以及每周开始日期和结束日期
2015/08/06 PHP
php简单创建zip压缩文件的方法
2016/04/30 PHP
PHP压缩图片功能的介绍
2019/03/21 PHP
IE JS无提示关闭窗口不提示的方法
2010/04/29 Javascript
Jquery+WebService 校验账号是否已被注册的代码
2010/07/12 Javascript
Javascript之旅 对象的原型链之由来
2010/08/25 Javascript
javascript jscroll模拟html元素滚动条
2012/12/18 Javascript
jquery获取html元素的绝对位置和相对位置的方法
2014/06/20 Javascript
node.js中的path.delimiter方法使用说明
2014/12/09 Javascript
jQuery的Ajax用户认证和注册技术实例教程(附demo源码)
2015/12/08 Javascript
Express实现前端后端通信上传图片之存储数据库(mysql)傻瓜式教程(一)
2015/12/10 Javascript
AngularJs 动态加载模块和依赖
2016/09/15 Javascript
angular 动态组件类型详解(四种组件类型)
2017/02/22 Javascript
仿vue-cli搭建属于自己的脚手架的方法步骤
2019/04/17 Javascript
vue axios post发送复杂对象问题
2019/06/04 Javascript
jQuery实现图片下载代码
2019/07/18 jQuery
微信小程序自定义胶囊样式
2020/12/27 Javascript
Python实现视频下载功能
2017/03/14 Python
Python列表推导式、字典推导式与集合推导式用法实例分析
2018/02/07 Python
Python计算不规则图形面积算法实现解析
2019/11/22 Python
简单了解Java Netty Reactor三种线程模型
2020/04/26 Python
美国指甲油品牌:Deco Miami
2017/01/30 全球购物
女士鞋子、包包和服装在线,第一款10美元:ShoeDazzle
2019/07/26 全球购物
瑞典香水、须后水和美容产品购物网站:Parfym-Klick.se
2019/12/29 全球购物
什么是java序列化,如何实现java序列化
2012/11/14 面试题
C#和SQL Server的面试题
2016/08/12 面试题
syb养殖创业计划书
2014/01/09 职场文书
工商管理专业自荐信
2014/06/03 职场文书
白鹤梁导游词
2015/02/06 职场文书
德能勤绩工作总结
2015/08/11 职场文书
django上传文件的三种方式
2021/04/29 Python
eval(cmd)与eval($cmd)的区别与联系
2021/07/07 PHP
一次Mysql update sql不当引起的生产故障记录
2022/04/01 MySQL
Android自定义ScrollView实现阻尼回弹
2022/04/01 Java/Android