1. 程式人生 > >利用Plupload解決大容量檔案上傳問題, 帶進度條和背景遮罩層

利用Plupload解決大容量檔案上傳問題, 帶進度條和背景遮罩層

大容量檔案上傳早已不是什麼新鮮問題,在.net 2.0時代,Html5也還沒有問世,要實現這樣的功能,要麼是改web.config,要麼是用flash,要麼是用一些第三方控制元件,然而這些解決問題的方法要麼很麻煩,比如改配置,要麼不穩定,比如檔案上G以後,上傳要麼死掉,要麼卡住,通過設定web.config並不能很好的解決這些問題。

這是一個Html5統治瀏覽器的時代,在這個新的時代,這種問題已被簡化並解決,我們可以利用Html5分片上傳的技術,那麼Plupload則是一個對此技術進行封裝的前端指令碼庫,這個庫的好處是可以自動檢測瀏覽器是否支援html5技術,不支援再檢測是否支援flash技術,甚至是sliverlight技術,如果支援,就使用檢測到的技術。

那麼這個庫到哪裡下載,怎麼搭建呢,比較懶的童鞋還是用Install-Package Plupload搞定吧,一個命令搞定所有事

下面給出一個例子,使用自已定義的控制元件來使用Plupload (Plupload也有自己的介面可以用),如下

這裡寫圖片描述

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); }); /******************************************************Plupload***********************************************************/

後臺 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;
        }
    }
}