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

namespace Print.DownloadFile
{
    /// <summary>
    /// Http下载文件类
    /// 支技断点续传功能
    /// </summary>
    public class HttpDownloadFile
    {
        #region<事件>
        public delegate void DownloadIngHandler(object sender, DownloadIngEventArgs e);
        /// <summary>
        /// 每收到一个文件下载数据时触发
        /// </summary>
        public event DownloadIngHandler onDownloadIng;
        public delegate void DownloadEndHandler(object sender, DownloadendEventArgs e);
        /// <summary>
        /// 一个文件下载完成时触发
        /// </summary>
        public event DownloadEndHandler onDownloadEnd;
        public delegate void ValidateMD5ErrorHandler(object sender, ValidateMD5ErrorEventArgs e);
        /// <summary>
        /// 下载完后验证MD5错误
        /// </summary>
        public event ValidateMD5ErrorHandler onValidateMD5Error;
        public delegate void ExceptionHandler(object sender, ExceptionEventArgs e);
        /// <summary>
        /// 出现异常时触发
        /// </summary>
        public event ExceptionHandler onException;
        #endregion<End事件>

        #region<成员变量与属性>
        /// <summary>
        /// 文件的总大小
        /// </summary>
        private long m_totalFileSize = 0;
        /// <summary>
        /// 当前已经下载的大小
        /// </summary>
        private long m_currFileSize = 0;
        /// <summary>
        /// 是否为续传
        /// </summary>
        private bool m_isKeep = false;
        /// <summary>
        /// 是否停止下载
        /// </summary>
        private bool m_isStop = false;
        /// <summary>
        /// 文件名,不含路径
        /// </summary>
        private string m_fileName;
        /// <summary>
        /// 文件下载完成后用于验证文件完整性的MD5值
        /// </summary>
        private string m_Md5;
        /// <summary>
        /// 下载资源的URL
        /// </summary>
        private string m_url;
        /// <summary>
        /// 下载时需要登录的用户名
        /// </summary>
        private string m_username = string.Empty;
        /// <summary>
        /// 下载时需要登录的用户密码
        /// </summary>
        private string m_userpwd = string.Empty;
        /// <summary>
        /// 要保存文件的路路径
        /// </summary>
        private string m_savePath;
        /// <summary>
        /// 下载资源的代理服务器
        /// </summary>
        private string m_proxyip = string.Empty;
        /// <summary>
        /// 下载资源的代理端口
        /// </summary>
        private string m_proxyport = null;
        /// <summary>
        /// 当前下载文件的ID
        /// </summary>
        private string m_id = string.Empty;
        #endregion<end 成员变量与属性>

        #region<构造方法>
        /// <summary>
        /// Http文件下载对象
        /// </summary>
        /// <param name="url">下载的资源</param>
        /// <param name="username">用户名</param>
        /// <param name="userpwd">登录密码</param>
        /// <param name="savepath">本地保存的路径,包含文件名</param>
        /// <param name="proxyip">代理服务器</param>
        /// <param name="proxyport">代理端口</param>
        /// <param name="MD5">文件的MD5值,用于验证文件完整性</param>
        /// <param name="id">文件信息保存在数据中的ID</param>
        public HttpDownloadFile(string url, string username, string userpwd, string savepath,
            string proxyip, string proxyport, string MD5, string id)
            : this(url, username, userpwd, savepath, MD5, id)
        {
            m_proxyip = proxyip;
            m_proxyport = proxyport;
        }
        /// <summary>
        /// Http文件下载对象
        /// </summary>
        /// <param name="url">下载的资源</param>
        /// <param name="username">用户名</param>
        /// <param name="userpwd">登录密码</param>
        /// <param name="savepath">本地保存的路径,包含文件名</param>
        /// <param name="MD5">文件的MD5值,用于验证文件完整性</param>
        /// <param name="id">文件信息保存在数据中的ID</param>
        public HttpDownloadFile(string url, string username, string userpwd, string savepath, string MD5, string id)
            : this(url, savepath, MD5, id)
        {
            m_username = username;
            m_userpwd = userpwd;
        }
        /// <summary>
        /// Http文件下载对象
        /// </summary>
        /// <param name="url">下载的资源</param>
        /// <param name="savepath">本地保存的路径,包含文件名</param>
        /// <param name="MD5">文件的MD5值,用于验证文件完整性</param>
        /// <param name="id">文件信息保存在数据中的ID</param>
        public HttpDownloadFile(string url, string savepath, string MD5, string id)
        {
            m_url = url;
            m_savePath = savepath;
            m_Md5 = MD5;
            m_fileName = savepath.Substring(savepath.LastIndexOf('\\') + 1);
            m_id = id;
        }
        #endregion<end构造方法>

        #region<方法>
        /// <summary>
        /// 开始下载文件
        /// </summary>
        public void StartDownloadFile()
        {
            m_isStop = false;
            string filePath = m_savePath.Substring(0, m_savePath.LastIndexOf('\\'));
            if (!Directory.Exists(filePath))

                Directory.CreateDirectory(filePath);
            FileStream fs = new FileStream(m_savePath, FileMode.OpenOrCreate);
            m_currFileSize = fs.Length;
            //如果是续传
            if (m_currFileSize > 0)
            {
                this.m_isKeep = true;
                fs.Seek(m_currFileSize, SeekOrigin.Current);
            }
            try
            {
                Uri uri = new Uri(m_url);
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
                if (!(string.IsNullOrEmpty(m_proxyip) || string.IsNullOrEmpty(m_proxyport)))
                {
                    WebProxy myproxy = new WebProxy(m_proxyip, Convert.ToInt32(m_proxyport));
                    myproxy.BypassProxyOnLocal = true;
                    request.Proxy = myproxy;
                }
                NetworkCredential credentials = new NetworkCredential(m_username, m_userpwd);
                request.Credentials = credentials;
                //如果是续传,并且已经传完的文件大小0;
                if (m_isKeep && m_currFileSize > 0)
                    request.AddRange(Convert.ToInt32(m_currFileSize.ToString()));
                //重新定位后的响应
                WebResponse v = request.GetResponse();

                //取文件大小
                m_totalFileSize = v.ContentLength; //+ m_currFileSize;
                if (m_currFileSize >= m_totalFileSize)
                {
                    fs.Close();
                    if (!string.IsNullOrEmpty(m_Md5))
                    {
                        string localFileMd5 = MD5Lib.CalcFileMD5(m_savePath);
                        if (!m_Md5.Equals(localFileMd5))
                        {
                            if (onValidateMD5Error != null)
                            {
                                onValidateMD5Error(this, new ValidateMD5ErrorEventArgs(m_id, m_Md5, localFileMd5));
                                return;
                            }
                        }
                        else
                        {
                            if (onDownloadEnd != null)
                            {
                                onDownloadEnd(this, new DownloadendEventArgs(m_id, m_fileName, m_savePath,
                                    m_Md5, m_totalFileSize.ToString()));
                            }
                        }
                    }
                    return;
                }

                Stream rStream = v.GetResponseStream();
                byte[] buffer = new byte[4096];
                int len;
                System.Threading.Timer m_timer = new System.Threading.Timer(new TimerCallback(FulshMemory));
                m_timer.Change(100, 5000);
                do
                {
                    len = rStream.Read(buffer, 0, buffer.Length);
                    if (len > 0)
                        fs.Write(buffer, 0, len);
                    m_currFileSize += len;
                    m_HandlerData += len;
                    if (onDownloadIng != null)
                        onDownloadIng(this, new DownloadIngEventArgs(m_id,m_totalFileSize, len, m_currFileSize, m_speed));
                } while (len > 0 && !m_isStop);
                fs.Close();
                rStream.Close();
                if (!m_isStop)
                {
                    if (!string.IsNullOrEmpty(m_Md5))
                    {
                        string localFileMd5 = MD5Lib.CalcFileMD5(m_savePath);
                        if (!m_Md5.Equals(localFileMd5))
                        {
                            if (onValidateMD5Error != null)
                            {
                                onValidateMD5Error(this, new ValidateMD5ErrorEventArgs(m_id, m_Md5, localFileMd5));
                                return;
                            }
                        }
                        else
                        {
                            if (onDownloadEnd != null)
                            {
                                onDownloadEnd(this, new DownloadendEventArgs(m_id, m_fileName, m_savePath,
                                    m_Md5, m_totalFileSize.ToString()));
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                fs.Close();
                if (ex.Message.Contains("(416) Requested Range Not Satisfiable"))
                {
                    if (!string.IsNullOrEmpty(m_Md5))
                    {
                        string localFileMd5 = MD5Lib.CalcFileMD5(m_savePath);
                        if (!m_Md5.Equals(localFileMd5))
                        {
                            if (onValidateMD5Error != null)
                            {
                                onValidateMD5Error(this, new ValidateMD5ErrorEventArgs(m_id, m_Md5, localFileMd5));
                                return;
                            }
                        }
                        else
                        {
                            if (onDownloadEnd != null)
                            {
                                onDownloadEnd(this, new DownloadendEventArgs(m_id, m_fileName, m_savePath,
                                    m_Md5, m_totalFileSize.ToString()));
                            }
                        }
                    }
                }
                else
                {
                    if (onException != null)
                        onException(this, new ExceptionEventArgs(m_id,"文件传输时出现的异常", ex));
                }
            }
        }
        /// <summary>
        /// 在归定的时间收到的数据
        /// </summary>
        private long m_HandlerData = 0;
        private string m_speed = "0k/s";
        /// <summary>
        /// 定时处理
        /// </summary>
        /// <param name="o"></param>
        private void FulshMemory(object o)
        {
            if (m_HandlerData != 0)
            {
                m_speed = Util.HRSize(m_HandlerData / 5) + "/s";
            }
            m_HandlerData = 0;
        }

        /// <summary>
        /// 停止下载文件
        /// </summary>
        public void StopDownloadFile()
        {
            m_isStop = true;
        }
        #endregion<end方法>
    }
}
using System;
using System.Collections.Generic;
using System.Text;

namespace Print.DownloadFile
{
    /// <summary>
    /// 文件下载结束
    /// </summary>
    public class DownloadendEventArgs : EventArgs
    {
        /// <summary>
        ///  构造方法
        /// </summary>
        /// <param name="id">文件信息在数据库保存的Id</param>
        /// <param name="fileName">文件名</param>
        /// <param name="localPath">保存的本地路径,包含文件名</param>
        /// <param name="md5">文件的MD5值</param>
        /// <param name="fileSize">文件大小</param>
        public DownloadendEventArgs(string id,string fileName, string localPath,string md5,string fileSize)
        {
            _fileName = fileName;
            _localPath = localPath;
            _id = id;
            _fileSize = fileSize;
            _md5 = md5;
        }
        private string _id;
        /// <summary>
        /// 获取文件信息在数据库保存的Id
        /// </summary>
        public string Id
        {
            get { return _id; }
        }
        private string _fileName;
        /// <summary>
        /// 获取下载的文件名
        /// </summary>
        public string FileName
        {
            get { return _fileName; }
        }

        private string _localPath;
        /// <summary>
        /// 获取保存在本地的路径
        /// </summary>
        public string LocalPath
        {
            get { return _localPath; }
        }
        private string _md5;
        /// <summary>
        /// 获取文件的MD5值
        /// </summary>
        public string Md5
        {
            get { return _md5; }
        }
        private string _fileSize;
        /// <summary>
        /// 获取文件的大小
        /// </summary>
        public string FileSize
        {
            get { return _fileSize; }
        }
    }
}
DownloadendEventArgs

相关文章: