无刷新大文件上传组件

大家好,今天和大家分享下无刷新上传大文件文件东西,先说明只讲关键部分.

大概如下图:

 

 

一,目标

(1)有3种默认颜色风格

(2)支持大文件上传

(3)可以中途停止

(4)有进度信息提示

二,简述

   一个文件在http下发送整体格式是:

 

-----------------------------7d51f321004ec

Content-Disposition: form-data; name="guid"

 

ea0032acb80b210becea0032acb80b2

-----------------------------7d51f321004ec

 

  

-----------------------------7d51f321004ec

Content-Disposition: form-data; name="m_file"; filename="D:/mypic/logo.png"

Content-Type: image/x-png

?PNG

  

IHDR   ]   &   ¦??Á   gAMA  ¯È7?é   tEXtSoftware Adobe ImageReadyqÉe<  ÂIDATxÚbüÿÿ?Ã0 ?@Ìļ@ü?¿fÇã0 t`b1 V?FÂ] ~>

@Ã)Ð?S½:?@Sÿ ¾ Äÿ?h8:2Ðbs â¯@| ?/´£ h¸ : ?ÊúP â@<??c h¤: °q§ñ' ?Ä?ø=@#-ÐÑS~"óA~_¡?å 4R¹Ò9Ý@,ÄË?¸?¯ÒÒR? é?ü@/ ÄeÐÏ2 n£UàÐh £P? ?Ó???7 ñb ÞLMK h4бE ?ÄPþV îâCÔ0 ???Ø<@, ­d8èà±2hf3ý>{q

 

-----------------------------7d51f321004ec--

 

大概是如上,一部分信息被删除,为的是简单起见...

最主要是是把乱码部分的内容用流二进制把它保存起来,并且写到文件中,就是达到上传的目的了..

至于实现过程我接下来我们慢慢的分析

 

 

(1)在B/S模式中,当文件在FORM中POST到服务机的过程中.我们一般都是在MOUDULE中把请求截下来..

 

 

 

 

internal abstract class BaseModule : IHttpModule
    {
        #region IHttpModule Members
     

        public void Dispose()
        {
           // throw new NotImplementedException();
        }

        public void Init(HttpApplication context)
        {
           
            //context.BeginRequest += new EventHandler(context_BeginRequest);
          
            context.AuthenticateRequest += new EventHandler(context_BeginRequest);
            //context.AuthorizeRequest += new EventHandler(context_AcquireRequestState);
            context.AuthenticateRequest+= new EventHandler(context_AcquireRequestState);
            //context.AuthorizeRequest += new EventHandler(context_BeginRequest);
            context.EndRequest += new EventHandler(context_EndRequest);
           // context.Error += new EventHandler(context_Error);
        }

        void context_AcquireRequestState(object sender, EventArgs e)
        {
            HttpApplication app = sender as HttpApplication;
           
            MySessionBegin(app, e);
        }

        void context_Error(object sender, EventArgs e)
        {
            HttpApplication app = sender as HttpApplication;
            MyError(app, e);
        }

        void context_EndRequest(object sender, EventArgs e)
        {
            HttpApplication app =sender as HttpApplication;
            MyEndRequest(app,e);
        }

        void context_BeginRequest(object sender, EventArgs e)
        {
            HttpApplication app = sender as HttpApplication;
            MyBeginRequest(app, e);

        }

        #endregion
        public abstract void MyBeginRequest(HttpApplication app, EventArgs e);
        public abstract void MyEndRequest(HttpApplication app, EventArgs e);
        public abstract void MyError(HttpApplication app, EventArgs e);
        public abstract void MySessionBegin(HttpApplication app, EventArgs e);
    }

 

 

继承上面的抽象类.实现module...

 

internal class WebModule : BaseModule
    {
        private  LogHelper log = null;
        private string tmpfolder = "~tmpfile";
        public WebModule()
        {
           
        }
        public override void MyBeginRequest(HttpApplication app, EventArgs e)
        {


            //在这里截信息...         
        }
        public override void MySessionBegin(HttpApplication app, EventArgs e)
        {
            this.UploadMethod(app);
        }
        public override void MyEndRequest(HttpApplication app, EventArgs e)
        {
            //throw new NotImplementedException();
            if(this.log!=null) log.Close();

           
        }
        public override void MyError(HttpApplication app, EventArgs e)
        {       
            this.Dispose();
        }

        #region 方法
        private HttpWorkerRequest GetWorkerRequest(HttpApplication app)
        {
            IServiceProvider m_provider = app.Context;
            new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
            return ((HttpWorkerRequest)m_provider.GetService(typeof(HttpWorkerRequest)));
        }
        private HttpWorkerRequest GetWorkerRequest()
        {
            IServiceProvider m_provider = HttpContext.Current;
            new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
            return ((HttpWorkerRequest)m_provider.GetService(typeof(HttpWorkerRequest)));
        }
        /// <summary>
        /// Get the upload file max Size from web.config.
        /// </summary>
        /// <returns></returns>
        private long GetUpLoadFileLength()
        {
            int m_MaxLength = 0;
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(Path.Combine(HttpContext.Current.Request.PhysicalApplicationPath, "web.config"));
            XmlNode node = xmlDocument.SelectSingleNode("configuration/system.web/httpRuntime/@maxRequestLength");
            if (node != null)
            {
                m_MaxLength = Convert.ToInt32(node.Value);
            }
            else
            {
                m_MaxLength = 1024;//1MB for default;
            }
            xmlDocument = null;
            return (m_MaxLength * 1024);
        }
        private bool IsUseSession()
        {
            string re = System.Configuration.ConfigurationManager.AppSettings["MarkUploadSession"];
            if (re == null || re == "") return false;
            bool t=true;
            if (bool.TryParse(re, out t))
                return t;
            else
                return false;
        }
        private string GetTmpFolder()
        {
           string re= System.Configuration.ConfigurationManager.AppSettings["MarkUpload"];
           return (re!=null) ? re : "~/markupload/";
        }
        private string GetKeyofMD()
        {
            string re=System.Configuration.ConfigurationManager.AppSettings["keyOfMD"];
            return re;
        }
        private bool CheckRefer(HttpApplication app)
        {
            string host =@"http://" + app.Request.Url.Host.ToLower();

            Uri obj=app.Request.UrlReferrer;
            if (obj == null) return false;
          
            string refer = obj.ToString().ToLower();
            return (refer.IndexOf(host) == 0);
        }
        private bool UploadMethod(HttpApplication app)
        {
            //this.log = new LogHelper("G://IIS_Path//TestMarkUpload//tmpfile_");
            //log.MaxSize = 1024 * 1024;
            //MyEncoder.encoding_ = app.Request.ContentEncoding;
            //log.Encod_write = MyEncoder.encoding_;
            //log.DateTimeFormat = "ms";
            //log.Write(app.Request.Url.AbsoluteUri);


            HttpWorkerRequest worker = this.GetWorkerRequest(app);

            string ct = worker.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentType);
            if (ct != null && string.Compare(ct, 0, MARKER.C_MARKER, 0, MARKER.C_MARKER.Length, true) == 0)
            {

              
                long total = long.Parse(worker.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength));
                if (total > 0)
                {
                    WorkType WT = new WorkType();
                    byte[] buf = new byte[WT.Size];
                    FormStream fs = null;
                    ReturnInfo Rinf = new ReturnInfo();
                    try
                    {
                        string boundary = "--" + ct.Substring(ct.IndexOf(MARKER.B_MARKER) + MARKER.B_MARKER.Length);
                        fs = new FormStream(boundary, app.Request.ContentEncoding, total, this.GetKeyofMD(), app.Server.MapPath(this.GetTmpFolder()));
                        fs.OnCreateFile += new FormStream.HandlerCreateFile(fs_OnCreateFile);
                        fs.OnCloased += new FormStream.HandlerOnClose(fs_OnCloased);
                       
                       
                        if (worker.GetPreloadedEntityBodyLength() > 0)
                        {
                            byte[] data = worker.GetPreloadedEntityBody();
                            total -= data.Length;
                            fs.Write(data, 0, data.Length);
                        }

                        while (total > 0 && worker.IsClientConnected() && total >= buf.Length)
                        {
                            if(WT.IsUseThread) System.Threading.Thread.Sleep(1);
                            int read = worker.ReadEntityBody(buf, buf.Length);
                            if (read > 0)
                            {
                                total -= read;
                                fs.Write(buf, 0, read);
                            }
                            else
                                break;

                        }
                        if (total > 0 && worker.IsClientConnected() && total < buf.Length)
                        {

                            int read = worker.ReadEntityBody(buf, buf.Length);
                            if (read > 0)
                            {
                                total -= read;
                                fs.Write(buf, 0, read);

                            }
                        }
                        Rinf.Id = 1;
                        Rinf.Ftotal = fs.Position - fs.Headlen-fs.EOF.Length-fs.CRLF.Length;
                        Rinf.Message = fs.FieldName["guid"];
                    }
                    catch (Exception e)
                    {
                        Rinf.Id = (e.Message == "stopping") ? -5 : -1;
                        Rinf.Ftotal = -3;
                        Rinf.Message = e.Message;
                        //log.Write(e.ToString());
                    }
                    finally
                    {
                        fs.Close();
                    }
                    app.Response.ContentType = "text/html";
                    app.Response.Write(JsonUtil.ToJsonString(Rinf));
                    app.Response.End();
                    return true;
                }
              
            }
            //this.log.Close();
            return false;

        }

        void fs_OnCloased(string guid)
        {
            HttpContext.Current.Application.Remove(guid);
        }

        void fs_OnCreateFile(Info info_,string guid)
        {
            HttpContext.Current.Application.Add(guid, info_);
        }
        private string ReplaceSpecal(string src)
        {
            if (src == null) return "";
            return src.Replace("/"", "").Replace("//","").Replace("/","").Replace("'", "").Replace(";", "").Replace("?", "").Replace(")", "").Replace("(", "").Replace(":", "");
        }
        #endregion
    }
}

 

至于如何设置module的东西我就不讲了...只讲下如何把流读出来(上面代码的UploadMethod函数就是度取流的函数,)并且把读到的流方如这么一个类

 

 

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Collections;

namespace MarkUpload
{
   
    internal class FormStream : Stream, IDisposable
    {
        public delegate void HandlerCreateFile(Info info_,string guid);
        public delegate void HandlerOnClose(string guid);
        public event HandlerCreateFile OnCreateFile;
        public event HandlerOnClose OnCloased;
        #region Declara
        Info info_ = null;
        /// <summary>
        /// 进度条信息
        /// </summary>
        public Info Info_
        {
            get { return info_; }
        }
        Speeds sp = new Speeds();

        Encoding _encoding;
        MemoryStream _headbytes;
        private long headlen;
        /// <summary>
        /// 头部实际长度
        /// </summary>
        public long Headlen
        {
            get { return headlen; }
            set { headlen = value; }
        }
        /// <summary>
        /// 总信息长度
        /// </summary>
        long Total = 0;
        /// <summary>
        /// 当前长度
        /// </summary>
        long _position=0;
        /// <summary>
        /// 结束整个流字符标记,也就是BOUNDARY+“--”
        /// </summary>
        public  byte[] EOF;
        /// <summary>
        /// Field开始标记行
        /// </summary>
        byte[] BOUNDARY;
        /// <summary>
        /// 标记头和实体的间隔行
        /// </summary>
        byte[] EOH;
        /// <summary>
        /// 某个实体行的结束标记行
        /// </summary>
        public byte[] CRLF;
        byte[] MD_;
        /// <summary>
        /// 判是否等待头信息完成
        /// </summary>
        bool _headerNeeded=true;
        /// <summary>
        /// 判断是否是文件体部分了
        /// </summary>
        ///
        string key_ = null;
        string tmp_path = null;
        FileStream fs_ = null;
        Dictionary<string, string> fieldName = new Dictionary<string, string>();

        public Dictionary<string, string> FieldName
        {
            get { return fieldName; }
        }
        #endregion


        #region Constructor
        /// <summary>
        ///
        /// </summary>
        /// <param name="boundary">特殊分割符号</param>
        /// <param name="encoding_">编码方式</param>
        /// <param name="total_">总提交大小</param>
        /// <param name="key">八位</param>
        /// <param name="tmp_path_">FullPath</param>
        public FormStream(string boundary, Encoding encoding_,long total_,string key,string tmp_path_)
        {
            headlen = 0;
            this._encoding = encoding_;
            this.BOUNDARY = this._encoding.GetBytes(boundary);
            this.EOF = this._encoding.GetBytes(boundary + "--/r/n");
            this.EOH = this._encoding.GetBytes("/r/n/r/n");
            this.CRLF = this._encoding.GetBytes("/r/n");
            this.MD_ = this._encoding.GetBytes(MARKER.MDSTR);
            this.Total = total_;
            this._headerNeeded=true;
            this._headbytes = new MemoryStream();
            this.key_ = key;
            this.tmp_path = tmp_path_;
            this.info_ = new Info();
        }
        #endregion

        #region StreamMethod 
        public override bool CanRead
        {
            get { return false; }
        }

        public override bool CanSeek
        {
            get { return false; }
        }

        public override bool CanWrite
        {
            get { return true; }
        }

        public override void Flush()
        {
            if (this._headbytes != null && this._headbytes.CanWrite)
                this._headbytes.Close();
            if (this.OnCloased != null)
            {
                if (!this._headerNeeded)
                    this.OnCloased(this.FieldName["guid"]);
            }
        }

        public override long Length
        {
            get { return this._position; }
        }

        public override long Position
        {
            get
            {
               return  this._position;
            }
            set
            {
                this._position = value;
            }
        }
        public void Close()
        {
            if (this.fs_ != null ) this.fs_.Close();
            if (this.OnCloased != null)
            {
                try
                {
                    string guid = this.FieldName["guid"];
                    this.OnCloased(guid);
                }
                catch (Exception e)
                { }
            }
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            throw new NotImplementedException();
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            throw new NotImplementedException();
        }

        public override void SetLength(long value)
        {
            throw new NotImplementedException();
        }
        private LogHelper log = null;

        public LogHelper Log
        {
            get {

                return log; }
            set { this.log = value; }

        }
        public override void Write(byte[] buffer, int offset, int count)
        {
            if (count <= 0 ) return;
            if (this.Total > 0 && this.Total <= this.Position) return;
          
            if (this._headerNeeded)//读头部信息
            {
                this._headbytes.Write(buffer, offset, count);

                byte[] buf = this._headbytes.GetBuffer();
                Dictionary<int,int> p=this.CheckHeadField(buf);
                if (p.Count == 3)//当3段都填写了之后
                {
                    this.FillTheHead(buf, p);
                }
            }
            else//写文件
            {
                long will=this._position+count;
                long file_end_p=this.Total-this.EOF.Length-this.CRLF.Length;
                if ((this._position + count) <= file_end_p)
                {
                    this.fs_.Write(buffer, offset, count);

                }
                else
                {
                    int shouldWrite=int.Parse((file_end_p - this._position).ToString());
                    this.fs_.Write(buffer, 0,shouldWrite);
                    count = shouldWrite;
                }

            }

            this._position += count;
            this.info_.Current = this._position;
            if (this.info_.Total < 0)
            {
                this.fs_.Close();
                File.Delete(Path.Combine(this.tmp_path, this.FieldName["guid"] + Path.GetExtension(this.FieldName["filename"])));
                throw new Exception("stopping");
            }
            this.sp.Current +=count;
            TimeSpan ts = DateTime.Now.Subtract(sp.DT);
            if(ts.TotalSeconds>=1)
            {
                this.info_.Speed = (double)(sp.Current / 1024);
                this.sp.Current = 0;
                this.sp.DT = DateTime.Now;
            }
        }
        #endregion

        #region 自定义方法
        private int IndexOf(byte[] buffer, byte[] checFor)
        {
            return this.IndexOf(buffer, checFor, 0,buffer.Length);
        }
        /// <summary>
        /// 取得checkFor字节数组在buffer出现的位置,不存在则返回-1
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="checkFor"></param>
        /// <param name="start_"></param>
        /// <returns></returns>
        private int IndexOf(byte[] buffer, byte[] checkFor,int start_)
        {
            return this.IndexOf(buffer, checkFor, start_, buffer.Length - start_);
        }
        private int IndexOf(byte[] buffer, byte[] checkFor, int start, int count)
        {
            int index = 0;
            int startPos = Array.IndexOf(buffer, checkFor[0], start);
            if (startPos != -1)
            {
                while ((startPos + index) < buffer.Length)
                {
                    if (buffer[startPos + index] == checkFor[index])
                    {
                        index++;
                        if (index == checkFor.Length)
                        {
                            return startPos;
                        }

                    }
                    else
                    {
                        startPos = Array.IndexOf<byte>(buffer, checkFor[0], startPos + index);
                        if (startPos == -1)
                        {

                            return -1;
                        }
                        index = 0;
                    }
                }
            }
            return -1;
        }

        /// <summary>
        /// 创建文件流
        /// </summary>
        /// <param name="buf">当前读取的头信息字节数组</param>
        /// <param name="start">截取头信息字节数组中文件部分的开始位置</param>
        private void CreateFileStrean(byte[] buf, int start)
        {
            string md = this.FieldName["mdstr"];
            string guid=this.FieldName["guid"];
            if (md == null || "" == md || guid == null || "" == guid)
            {
                throw new Exception("包格式错误");
            }
            else
            {
                //this.myExt + "@" + this.max_Size + "@" + DateTime.Now.ToString("dd");
                string source = MD.Decode(md, this.key_);
                string[] Mdpart = source.Split(new char[] { '@' }, StringSplitOptions.RemoveEmptyEntries);
                if (long.Parse(Mdpart[1]) < (this.Total - this.headlen))
                    throw new Exception("大小不匹配");
                string filename_=this.FieldName["filename"];
                string ext=Path.GetExtension(filename_);
                System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex(Mdpart[0], System.Text.RegularExpressions.RegexOptions.IgnoreCase);
                if (!reg.IsMatch(ext))
                { throw new Exception("文件类型不匹配"); }
               
                if (!Directory.Exists(this.tmp_path)) Directory.CreateDirectory(this.tmp_path);
                this.fs_= File.Create(Path.Combine(this.tmp_path, guid + ext));
                long File_End_Poision=this.Total - this.EOF.Length-this.CRLF.Length;
                if ( File_End_Poision>= buf.Length)
                {
                    this.fs_.Write(buf,start, buf.Length - start);

                }
                else
                {
                    this.fs_.Write(buf, start,int.Parse((File_End_Poision - start).ToString()));
                }

                this._headbytes.Close();
                if (this.OnCreateFile != null)
                {
                    this.info_.Total = this.Total;
                    this.info_.Filename = Path.GetFileName(filename_);
                    this.OnCreateFile(this.info_, guid);
                }
            }

        }

        /// <summary>
        /// 填写头信息
        /// </summary>
        /// <param name="buf">头信息的数组</param>
        /// <param name="p">分段信息</param>
        private void FillTheHead(byte[] buf,Dictionary<int,int> p)
        {
            foreach (int start in p.Keys)
            {
                int end=p[start];
                string data = this._encoding.GetString(buf,start,end-start);
                string[] tmp=System.Text.RegularExpressions.Regex.Split(data,";");
                if (tmp.Length > 2)
                {
                   // int index = tmp[1].IndexOf('"');
                    string name = "filename";

                    int index=tmp[2].IndexOf('"')+1;
                    string value = tmp[2].Substring(index, tmp[2].IndexOf('"', index + 1)-index);
                    this.FieldName.Add(name.ToLower(), value);
                    this.headlen = end +this.EOH.Length;
                    this._headerNeeded = false;
                    this.CreateFileStrean(buf, end + this.EOH.Length);
                    break;
                }
                else
                {
                    int index = tmp[1].IndexOf('"')+1;
                    string name = tmp[1].Substring(index, tmp[1].IndexOf('"', index + 1) - index);
                    int start_=end+this.EOH.Length;
                    int end_=this.IndexOf(buf,this.BOUNDARY,start_);
                    string field_data = this._encoding.GetString(buf, start_, end_ - start_ - this.CRLF.Length);
                    this.FieldName.Add(name.ToLower(), field_data);
                }
            }
        }
        /// <summary>
        /// 取得头信息各分段
        /// </summary>
        /// <param name="buf">头信息的字节数组</param>
        /// <returns>各字段的分段信息</returns>
        private Dictionary<int,int> CheckHeadField(byte[] buf)
        {
            int start = 0;
            Dictionary<int, int> p = new Dictionary<int, int>();
            while(true)
            {
                int boundary_p = this.IndexOf(buf, this.BOUNDARY, start);
                int end = this.IndexOf(buf, this.EOH, boundary_p+this.BOUNDARY.Length);
                if (boundary_p>=0 && (end-boundary_p) > 0)
                {

                    p.Add(boundary_p+this.BOUNDARY.Length,end);
                    start = end;
                }
                else
                {
                    break;
                }
            }
            if (buf.Length >= 409600) throw new Exception("Head too long or can not be load");
            return p;
        }
        #endregion
    }
}

 

 

 

这样可能有点乱..大家先凑合着看吧,过些天在把源代码传上..急要源代码请留下邮箱吧..

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值