利用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 读取元素的CSS信息的代码
Feb 07 Javascript
window.open以post方式将内容提交到新窗口
Dec 26 Javascript
jquery解决图片路径不存在执行替换路径
Feb 06 Javascript
Javascript实现滑块滑动改变值的实现代码
Apr 12 Javascript
jquery+css实现的红色线条横向二级菜单效果
Aug 22 Javascript
javascript实现label标签跳出循环操作
Mar 06 Javascript
javascript中利用柯里化函数实现bind方法【推荐】
Apr 29 Javascript
js替换字符串中所有指定的字符(实现代码)
Aug 17 Javascript
vue.js实现表格合并示例代码
Nov 30 Javascript
拖动时防止选中
Feb 03 Javascript
vue实现页面加载动画效果
Sep 19 Javascript
微信小程序如何获取手机验证码
Nov 04 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
在MongoDB中模拟Auto Increment的php代码
2011/03/06 PHP
CI框架中通过hook的方式实现简单的权限控制
2015/01/07 PHP
CodeIgniter记录错误日志的方法全面总结
2016/05/17 PHP
php readfile()修改文件上传大小设置
2017/08/11 PHP
php支付宝APP支付功能
2020/07/29 PHP
动态控制Table的js代码
2007/03/07 Javascript
JavaScript中的函数的两种定义方式和函数变量赋值
2014/05/12 Javascript
深入学习JavaScript中的Rest参数和参数默认值
2015/07/28 Javascript
解决angular的$http.post()提交数据时后台接收不到参数值问题的方法
2015/12/10 Javascript
Vue.js每天必学之Class与样式绑定
2016/09/05 Javascript
Vue.js系列之vue-router(上)(3)
2017/01/03 Javascript
Javascript for in的缺陷总结
2017/02/03 Javascript
js数字滑动时钟的简单实现(示例讲解)
2017/08/14 Javascript
JS/jQuery实现DIV延时几秒后消失或显示的方法
2018/02/12 jQuery
Java设计中的Builder模式的介绍
2018/03/22 Javascript
使用sessionStorage解决vuex在页面刷新后数据被清除的问题
2018/04/13 Javascript
vue Tab切换以及缓存页面处理的几种方式
2019/11/05 Javascript
vue实现短信验证码输入框
2020/04/17 Javascript
Js和VUE实现跑马灯效果
2020/05/25 Javascript
javascript前端和后台进行数据交互方法示例
2020/08/07 Javascript
[01:13:18]Secret vs Infamous 2019国际邀请赛淘汰赛 败者组 BO3 第一场 8.23
2019/09/05 DOTA
python实现批量修改图片格式和尺寸
2018/06/07 Python
python中round函数如何使用
2020/06/19 Python
python计算auc的方法
2020/09/09 Python
HTML5新控件之日期和时间选择输入的实现代码
2018/09/13 HTML / CSS
html5需遵循的6个设计原则
2016/04/27 HTML / CSS
英国家喻户晓的折扣商场:TK Maxx
2017/05/26 全球购物
荷兰网上药店:Drogisterij.net
2019/09/03 全球购物
State Cashmere官网:半零售价可持续蒙古羊绒
2020/02/26 全球购物
大学社团计划书
2014/05/01 职场文书
领导班子在批评与自我批评座谈会上的发言
2014/09/28 职场文书
财产分割协议书范本
2014/11/03 职场文书
铁路安全反思材料
2014/12/24 职场文书
清明节网上祭英烈寄语2015
2015/03/04 职场文书
运动会加油稿30字
2015/07/21 职场文书
python函数的两种嵌套方法使用
2022/04/02 Python