【www.gdgbn.com--网络相关】

asp教程.net实现 文件断点续传的功能
1.文件断点续传的功能由接收方管理。

2.在每次文件接收中断的时候,会创建一个等待续传的项目对象,使用resumedfileitem类来封装相关的信息。

 

   ///


    /// 有可能被续传的项目。
    ///

    public class resumedfileitem
    {
        #region senderid
        private string senderid;
        ///
        /// 发送者的id。
        ///

        public string senderid
        {
            get { return senderid; }
            set { senderid = value; }
        }
        #endregion

        #region originfilepath
        private string originfilepath;
        ///


        /// 发送方发送的文件的全路径。
        ///

        public string originfilepath
        {
            get { return originfilepath; }
            set { originfilepath = value; }
        }
        #endregion

        #region originfilesize
        private long originfilesize = 0;
        ///


        /// 发送方发送的文件的大小。
        ///

        public long originfilesize
        {
            get { return originfilesize; }
            set { originfilesize = value; }
        }
        #endregion

        #region originfilelastupdatetime
        private datetime originfilelastupdatetime;
        ///


        /// 发送方发送的文件的最后修改日期。
        ///

        public datetime originfilelastupdatetime
        {
            get { return originfilelastupdatetime; }
            set { originfilelastupdatetime = value; }
        }
        #endregion

        #region localtempfilesavepath
        private string localtempfilesavepath;
        ///


        /// 接收的临时文件的存储路径
        ///

        public string localtempfilesavepath
        {
            get { return localtempfilesavepath; }
            set { localtempfilesavepath = value; }
        }
        #endregion

        #region localfilesavepath
        private string localfilesavepath;
        ///


        /// 接收的文件存储路径
        ///

        public string localfilesavepath
        {
            get { return localfilesavepath; }
            set { localfilesavepath = value; }
        }
        #endregion

        #region receivedcount
        private long receivedcount = 0;
        ///


        /// 已经接收了多少字节数。
        ///

        public long receivedcount
        {
            get { return receivedcount; }
            set { receivedcount = value; }
        }
        #endregion

        #region disrupttedtime
        private datetime disrupttedtime = datetime.now;
        ///


        /// 接收中断的时间。
        ///

        public datetime disrupttedtime
        {
            get { return disrupttedtime; }
            set { disrupttedtime = value; }
        }
        #endregion
    }

      为何要记录如此多的信息了?这是为了当发送方再次发送同一文件给接收方时,接收方可以依据这些信息进行匹配,是否可以找到一个续传的项目,如果匹配成功,则表示可以进行续传。

      要记录的这些信息从哪里获取了?首先,是发送方在发送文件的时候,会将文件的相关信息告知接收方,如 被发送文件的全路径、被发送文件的大小、被发送的文件的最后修改日期等等;其次,当接收方接收文件时,就知道了临时文件的存储路径、正式文件的存储路径;再次,当文件传输中断的时刻,可以知道当前的文件已经被传递了多少字节。有了这些信息,断点续传才成为可能。  

 

3.使用iresumedfilemanager将所有的续传项目管理起来。

  

  public interface iresumedfilemanager
    {
        ///


        /// 当一个续传项超过多长时间没被使用,则将其移除,同时删除对应的临时文件。单位:秒。默认值:600。
        ///

        int ttl4resumedfileitem { get; set; }

        ///


        /// 是否启用文件的断点续传功能。默认值 true。
        ///

        bool enabled { get; set; }

        iagilelogger esflogger { set; }

        void initialize();

        void add(resumedfileitem resumedfileitem);

        ///


        /// 当接收一个文件之前,先看能否找到续传的匹配项(同时判断临时文件是否存在)。如果没有匹配,则返回null。
        ///

        resumedfileitem mapping4receive(transmittingfileinfo fileinfo);

        //


        /// 移除续传项。
        ///

        /// 要移除的续传项
        /// 是否同时删除临时文件
        void remove(resumedfileitem resumedfileitem, bool deletetempfile);       
    }
   

resumedfilemanager提供了定时删除过期的续传项目的功能,比如,一个续传项目在文件中断传输以后的10分钟内都没被激活,则视其为过期项目,将会被resumedfilemanager从内存中删除。这样就避免累积很多无效的续传项目对象,而浪费内存。

      resumedfilemanager的remove方法用于从内存中移除某个续传项目,其第二个参数表示是否删除临时文件,当某个续传项目因过期而被删除时,这时必须将临时文件也删除掉,以释放硬盘空间 -- 特别是对于作为文件服务器的服务端,这点更是重要的,否则,众多永远也不会被用到的临时文件将会浪费大量的硬盘空间。如果是因为找到匹配项而从管理器中移除续传项时,则不能删除临时文件,因为接下来临时文件会被继续使用。

 

4.当接收方在接收一个文件之前,首先调用iresumedfilemanager的mapping4receive方法寻找续传匹配项。当同时满足三个条件时(即originfilepath、originfilesize、originfilelastupdatetime),匹配才算成功。

if (item.originfilepath == fileinfo.originfilepath && item.originfilesize == fileinfo.filesize && item.originfilelastupdatetime == fileinfo.originfilelastupdatetime)
                    {
                        return item;
                    }

      如此,可以保证续传的文件与上次传输中断的文件是同一个文件。

 

5.当找到匹配项时,可以询问用户是否接受续传,esplus通过回调ifilebusinesshandler.readytoacceptfileasyn方法得到回复。

 string readytoacceptfileasyn(string senderid, string filename, long filelength, string comment, string fileid, resumedfileitem resumedfileitem);            
      如果返回值为null,表示拒绝接收;如果返回的存储路径与上次的存储路径相同,则表示同意续传;如果返回新的路径,则表示要求发送方重新发送整个文件。框架根据该方法的返回值而决定是否在后台启动续传。

   

6.如果同意续传,则接收方会告知发送方已接收的字节数,发送方可以从文件的对应偏移处开始发送后续数据。

rejectoracceptfilecontract协议说明了这一点。

    public class rejectoracceptfilecontract
    {
        #region fileid
        private string fileid;
        public string fileid
        {
            get { return fileid; }
            set { fileid = value; }
        }
        #endregion

        #region agree
        private bool agree;
        public bool agree
        {
            get { return agree; }
            set { agree = value; }
        }
        #endregion     

        #region receivedcount4resumefile
        private long receivedcount4resumefile = 0;
        ///


        /// 如果值非0,则表示续传,指示已经传递了多少字节。
        ///

        public long receivedcount4resumefile
        {
            get { return receivedcount4resumefile; }
            set { receivedcount4resumefile = value; }
        }
        #endregion
    }
 

7.如果续传开始,则接收方首先需要打开原始的临时文件,并寻址到正确的偏移处。

 this.fstream = new filestream(this.tempfilepath, filemode.open);
 this.fstream.seek(item.receivedcount, seekorigin.begin);


 

8.接下来就和以前一样进行正常的文件传输了。这样的设计,可以支持同一文件的无限次断点续传,也就是说,你在传送一个巨大文件的时候,哪怕中途断网很多次,也没关系,你不需要额外地重复传递哪怕一个字节。

 

本文来源:http://www.gdgbn.com/jiaocheng/28974/