1. 程式人生 > >asp.net單檔案帶進度條上傳

asp.net單檔案帶進度條上傳

        最近做專案中遇到很多問題,比如帶進度條的檔案上傳,看了網上很多資料還沒找到真正意義上的ASP.NET實現進度條上傳(可能是我沒找到),下面我來跟大家分享一下我實現的這個程式。

首先看下介面效果,當然你可以完全修改介面為你自己所用。(該截圖為google瀏覽器版本 42.0.2311.90截圖)

       先解釋一下這個程式,該程式採用了jquery框架,實現了小檔案上傳,不超過80Mb,可以在web.config檔案中進行相應的配置,但是有個最大值,具體需要檢視msdn。開發環境採用visual studio 2013 .net framework 4.5,執行的時候大家注意一下是否滿足要求,好了,下面直入正題。

先來看看實現原理。基本原理:一個頁面進行檔案上傳,另外一個頁面去監聽這個檔案上傳了多少。

       這裡面有兩個地方需要解釋一下:第一個,如何知道監聽的這個檔案就是上傳的這個檔案?實現機制很簡單,就是讓asp.net產生一個唯一的guid,這個id序號是唯一的,通過ajax取出來賦值給一個隱藏欄位;第二個,如何獲取guid標誌的檔案資訊?通過asp.net快取機制實現,上傳的過程中,不斷的將上傳資訊往快取裡面寫,直到檔案上傳完成,而在另外一個通過guid獲取快取的資訊,資訊包括你想要的資訊,比如上傳了多少位元組、消耗了多長時間等。好了,要點就解釋到這裡,有疑問的話給我留言。

       下面來說說具體的實現:

        檔案目錄結構如下:

 

         index.htm就是檔案上傳頁面,提交form給UploadHandler目錄下的Default.aspx,以實現檔案上傳。

ProgressHandler目錄下三個檔案為Abort.ashx、GenericGuid.ashx,Handler.ashx功能分別為:根據Guid取消正在上傳的檔案,生成Guid,根據Guid獲取上傳資訊。

        第一步:建立index.htm頁面,這個上傳頁面,需要注意的就是需要一個隱藏的iframe,並且名字為form提交的目標。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>ASP.NET Ajax檔案上傳進度條示例</title>
    <meta name="author" content="李檢全" />
    <link href="Styles/base.css" rel="stylesheet" type="text/css" />
    <script src="Scripts/jquery-1.4.2.min.js" type="text/javascript"></script>
    <script src="Scripts/jquery-ui-1.8.2.custom.min.js" type="text/javascript"></script>
    <script src="Scripts/ljq.lib.js" type="text/javascript"></script>
    <script src="Scripts/Ajax/GuidGet.js" type="text/javascript"></script>
    <script src="Scripts/Ajax/ajax-progress-upload.js" type="text/javascript"></script>
</head>
<body>
    <div id="upload_demo">
        <div class="title">ASP.NET Ajax 檔案上傳進度條示例</div>
        <form action="UploadHandler/Default.aspx" enctype="multipart/form-data" method="post" target="upload_hidden_iframe">
            <input id="guid" name="guid" value="" type="hidden" />
            <p>*本程式適合小檔案上傳,不超過80Mb</p>
            <p>檔案地址</p>
            <input name="upload_file" type="file" />
            <br />
            <p>檔案描述</p>
            <textarea name="description_file"></textarea>
            <br />
            <br />
            <input type="submit" value="上傳檔案" />
        </form>
    </div>
    <div id="back_panel"></div>
    <div id="upload_panel">
        <div id="upload_title">檔案上傳</div>
        <div id="upload_content">

            <ul>
                <li id="finished_percent">正在準備上傳...</li>
                <li><div id="upload_bar"><div id="upload_progress"></div></div></li>
                <li id="upload_speed"></li>
                <li id="upload_costTime"></li>
                <li id="upload_fileSize"></li>
                <li id="upload_fileName"></li>
            </ul>

            <div id="upload_detail"></div>
            <div id="upload_choose">
                <span id="upload_cancel">取消</span><span id="upload_submit">確定</span>
            </div>
        </div>
    </div>
    <iframe name="upload_hidden_iframe" style="display:none;"></iframe>


</body>
</html>

        第二步,建立GenerateGuid.ashx檔案,作用就是生成唯一的Guid.

<%@ WebHandler Language="C#" Class="ProgressHandler.Handler" %>

using System;
using System.Web;
using System.Xml.Linq;

namespace ProgressHandler
{
    public class Handler : IHttpHandler
    {
        /// <summary>
        /// 獲得上傳檔案的GUID
        /// </summary>
        /// <param name="context">當前請求實體</param>
        /// <creattime>2015-06-28</creattime>
        /// <author>FreshMan</author>
        public void ProcessRequest(HttpContext context)
        {
            context.Response.Charset = "utf-8";
            context.Response.ContentType = "application/xml";
            var guid = Guid.NewGuid().ToString();
            var doc = new XDocument();
            var root = new XElement("root");

            var xGuid = new XElement("guid", guid);
            root.Add(xGuid);
            doc.Add(root);
            context.Response.Write(doc.ToString());
            context.Response.End();
        }

        public bool IsReusable
        {
            get { return false; }
        }

    }
}

        第三步,建立Default.aspx檔案,用於提交表單時上傳檔案。

using System;

namespace UploadHandler
{
    public partial class UploadHandlerDefault : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            string guid = Request.Params["guid"];
            UploadUtil utilHelp = new UploadUtil(this, guid);
            utilHelp.Upload();
        }
    }
}

        上傳核心程式碼:

using System;
using System.Web;
using System.IO;
using System.Configuration;
using System.Web.UI;
using System.Web.Caching;
using System.Threading;
public class UploadUtil
{
    private Stream _reader;
    private FileStream _fStream;
    private const int Buffersize = 10000;
    private readonly string _filePath =new Page().Server.MapPath(ConfigurationManager.AppSettings["upload_folder"]);
    private readonly Page _page;
    private readonly string _guid;
    public UploadUtil(Page page, string guid)
	{
        _page = page;
        _guid = guid;
	}
    public void Upload()
    {
        if (_page.Request.Files.Count > 0)
        {
            DoUpload(_page.Request.Files[0]);
        }
    }
    private void DoUpload(HttpPostedFile postedFile)
    {
        bool abort = false;
        string uploadFilePath = _filePath + DateTime.Now.ToFileTime()+"//";
        if (!Directory.Exists(uploadFilePath))
        {
            Directory.CreateDirectory(uploadFilePath);
        }
        string uploadFileName = postedFile.FileName;
        DownloadingFileInfo info = new DownloadingFileInfo(uploadFileName, postedFile.ContentLength, postedFile.ContentType);
        object fileObj = HttpContext.Current.Cache[_guid];
        if (fileObj != null)
        {
            HttpContext.Current.Cache.Remove(_guid);
        }
        HttpContext.Current.Cache.Add(_guid, info, null, DateTime.Now.AddDays(1), TimeSpan.Zero, CacheItemPriority.AboveNormal, null);
        DateTime begin=DateTime.Now.ToLocalTime();
        _fStream = new FileStream(uploadFilePath + uploadFileName, FileMode.Create);
        _reader = postedFile.InputStream;
        byte []buffer=new byte[Buffersize];
        int len = _reader.Read(buffer,0,Buffersize);

        while (len > 0&&!abort)
        {
            _fStream.Write(buffer,0,len);
            DateTime end = DateTime.Now.ToLocalTime();
            info.CostTime = (long)(end - begin).TotalMilliseconds;
            info.FileFinished += len;

            //模擬延時用,實際應用的時候登出他
            Thread.Sleep(1000);

            HttpContext.Current.Cache[_guid] = info;
            abort=((DownloadingFileInfo)HttpContext.Current.Cache[_guid]).Abort;
            len = _reader.Read(buffer,0,Buffersize);
        }
      
        _reader.Close();
        _fStream.Close();
        if (abort)
        {
            if (File.Exists(uploadFilePath + uploadFileName))
            {
                File.Delete(uploadFilePath + uploadFileName);
            }
        }
    }
    
}

          第四步,建立Handler.ashx檔案,用於檢視檔案上傳情況。

<%@ WebHandler Language="C#" Class="ProgressHandler.Handler" %>

using System.Web;
using System.Xml.Linq;

namespace ProgressHandler
{
    public class Handler : IHttpHandler
    {
        /// <summary>
        /// 獲得上傳檔案的進度
        /// </summary>
        /// <param name="context">當前請求實體</param>
        /// <creattime>2015-06-28</creattime>
        /// <author>FreshMan</author>
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "application/xml";
            context.Response.Charset = "utf-8";
            var guid = context.Request.Form["guid"];
            var info = context.Cache[guid] as DownloadingFileInfo;
            var doc = new XDocument();
            var root = new XElement("root");
            if (info != null)
            {
                var fileName = new XElement("fileName", info.FileName);
                var fileFinished = new XElement("fileFinished", info.FileFinished);
                var fileSize = new XElement("fileSize", info.FileSize);
                var costTime = new XElement("costTime", info.CostTime);
                var fileState = new XElement("fileState", info.FileState);
                var speed = new XElement("speed", info.Speed);
                var percent = new XElement("percent", info.Percent);
                var abort = new XElement("abort", false);
                root.Add(fileName);
                root.Add(fileFinished);
                root.Add(fileSize);
                root.Add(costTime);
                root.Add(fileState);
                root.Add(speed);
                root.Add(percent);
                if (info.Abort)
                {
                    abort.Value = info.Abort.ToString();
                    context.Cache.Remove(guid);
                }
                if (info.FileState == "finished")
                {
                    context.Cache.Remove(guid);
                }
            }
            else
            {
                var none = new XElement("none", "no file");
                root.Add(none);
            }
            doc.Add(root);
            context.Response.Write(doc.ToString());
            context.Response.End();
        }

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

             第五步,建立Abort.ashx檔案,用於取消上傳。

<%@ WebHandler Language="C#" Class="ProgressHandler.Abort" %>
using System.Web;
using System.Xml.Linq;

namespace ProgressHandler
{
    public class Abort : IHttpHandler
    {
        /// <summary>
        /// 取消上傳處理程式
        /// </summary>
        /// <param name="context">當前請求實體</param>
        /// <creattime>2015-06-28</creattime>
        /// <author>FreshMan</author>
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "application/xml";
            context.Response.Charset = "utf-8";
            var guid = context.Request.Form["guid"];
            var abort = !string.IsNullOrEmpty(context.Request.Form["abort"]);
            var info = context.Cache[guid] as DownloadingFileInfo;
            if (info != null)
            {
                info.Abort = abort;
                context.Cache[guid] = info;
            }
            var doc = new XDocument();
            var root = new XElement("root");
            var flag = new XElement("flag", info == null ? "false" : "true");
            root.Add(flag);
            doc.Add(root);
            context.Response.Write(doc.ToString());
            context.Response.End();
        }

        public bool IsReusable
        {
            get { return false; }
        }

    }
}

       好了,下面就是編寫javascript指令碼了,我引用了jquery這個框架,另外還用了ui框架。

       核心程式碼是ajax-progress-upload.js檔案,另外還有一個獲取guid的檔案。

$(document).ready(function () {
    var _guid_url = "ProgressHandler/GenerateGuid.ashx";
    var _progress_url = "ProgressHandler/Handler.ashx";
    var _abort_url = "ProgressHandler/Abort.ashx";
    var _target = "#guid";
    var _guid = "";
    var _cancel = false;
    var _timer;
    LJQ.setGuid(_target, _guid_url);
    $("#upload_panel").draggable({ handle: "#upload_title" });
    $("#upload_choose span").hover(function () {
        $(this).css({
            "color": "#f6af3a",
            "border": "1px solid #e78f08"
        });
    }, function () {
        $(this).css({
            "color": "#1c94cd",
            "border": "1px solid #ddd"
        });
    });
    $("#upload_cancel").click(function () {
        $.ajax({
            url: _abort_url,
            data: { guid: _guid, abort: true },
            dataType: "xml",
            type: "post",
            success: function () {

                $("#upload_panel").fadeOut('fast');
                $("#back_panel").fadeOut(1000);
                window.clearInterval(_timer);
            }
        });


    });
    $("#upload_submit").click(function () {
        $("#upload_panel").fadeOut('fast');
        $("#back_panel").fadeOut("1000");
    });
    $("form").submit(function () {
        _guid = $(_target).val();
        if ($("input[name='upload_file']").val() == "") {
            alert("未指定上傳檔案!");
            return false;
        }
        $("#upload_progress").css("width", "0%");
        $("#finished_percent").html("準備上傳...");
        $("#upload_speed").html("");
        $("#upload_fileName").html("");
        $("#upload_fileSize").html("");
        $("#upload_costTime").html("");
        var _option = {
            url: _progress_url,
            data: { guid: _guid },
            dataType: "xml",
            type: "post",
            beforeSend: function () {
                $("#back_panel").fadeTo('fast', '0.5');
                $("#upload_panel").fadeIn('1000');
            },
            success: function (response) {

                if ($(response).find("root abort").text() == "true") {
                    $("#upload_panel").fadeOut('fast');
                    $("#back_panel").fadeOut(1000);
                    window.clearInterval(_timer);
                }

                else if ($(response).find("root none").text() == "no file") {

                }
                else {
                    var _percent = ($(response).find("root percent").text() * 100);
                    var _speed = $(response).find("root speed").text();
                    var _fileSize = $(response).find("root fileSize").text();
                    var _upload_costTime = $(response).find("root costTime").text();
                    if (parseInt(_speed) < 1024) {
                        _speed = LJQ.toFix(_speed) + "Kb";
                    } else {
                        _speed = LJQ.toFix(_speed / 1024) + "Mb";
                    }

                    if (parseInt(_fileSize) / 1024 < 1024) {
                        _fileSize = LJQ.toFix(_fileSize / 1024) + "Kb";
                    } else if (parseInt(_fileSize) / 1024 / 1024 < 1024) {
                        _fileSize = LJQ.toFix(_fileSize / 1024 / 1024) + "Mb";
                    } else {
                        _fileSize = LJQ.toFix(_fileSize / 1024 / 1024 / 1024) + "Gb";
                    }

                    if (_upload_costTime < 1000) {
                        _upload_costTime = _upload_costTime + "毫秒";
                    } else if (_upload_costTime / 1000 < 60) {
                        _upload_costTime = parseInt(_upload_costTime / 1000) + "秒" + _upload_costTime % 1000 + "毫秒";
                    } else {
                        _upload_costTime = parseInt(_upload_costTime / 1000 / 60) + "分" + parseInt((_upload_costTime % 60000) / 1000) + "秒" + _upload_costTime % 1000 + "毫秒";
                    }
                    $("#upload_progress").css("width", parseInt(_percent) + "%");
                    $("#finished_percent").html("完成百分比:" + LJQ.toFix(_percent) + "%");
                    $("#upload_speed").html("上傳速度:" + _speed + "/sec");
                    $("#upload_fileName").html("檔名稱:" + $(response).find("root fileName").text());
                    $("#upload_fileSize").html("檔案大小:" + _fileSize);
                    $("#upload_costTime").html("上傳耗時:" + _upload_costTime);
                    if (_percent >= 100) {

                        window.clearInterval(_timer);
                        $("#finished_percent").html("<span style='color:green;'>檔案上傳完成</span>");
                    }
                    if (_cancel) {
                        window.clearInterval(_timer);
                    }
                }

            },
            error: function () { }
        };

        _timer = window.setInterval(function () { $.ajax(_option); }, 1000);

    });

});
          以上為程式碼的主要部分。專案原始碼下載請點選這裡

       我是小白(FreshMan:如有指教可聯絡QQ:1174632606)