转:Http下载文件类 支技断点续传功能
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; } } } }
using System; using System.Collections.Generic; using System.Text; namespace Print.DownloadFile { /// <summary> /// 文件正在下载 /// </summary> public class DownloadIngEventArgs:EventArgs { /// <summary> /// 构造方法 /// </summary> /// <param name="id">文件的ID</param> /// <param name="totalFileSize">文件总大小</param> /// <param name="currFileSize">本次下载数据</param> /// <param name="downloadFileEd">已经下载的文件大小</param> public DownloadIngEventArgs(string id,long totalFileSize, int currFileSize, long downloadFileEd,string speed) { this._id = id; this._totalFileSize = totalFileSize; this._currFileSize = currFileSize; this._downloadFileSizeEd = downloadFileEd; this._speed = speed; } private string _id; /// <summary> /// 获取文件的ID /// </summary> public string Id { get { return _id; } } private long _totalFileSize; /// <summary> /// 获取文件总大小 /// </summary> public long TotalFileSize { get { return _totalFileSize; } } private int _currFileSize; /// <summary> /// 获取本次下载的大小 /// </summary> public int CurrFileSize { get { return _currFileSize; } } private long _downloadFileSizeEd; /// <summary> /// 获取已经下载的文件大小 /// </summary> public long DownloadFileSizeEd { get { return _downloadFileSizeEd; } } private string _speed; /// <summary> /// 获取下载速度 /// </summary> public string Speed { get { return _speed; } } } }
using System; using System.Collections.Generic; using System.Text; namespace Print.DownloadFile { public class ExceptionEventArgs : EventArgs { /// <summary> /// 构造方法 /// </summary> /// <param name="id">文件的ID</param> /// <param name="info">抛出异常的描述</param> /// <param name="ex">抛出的异常对象</param> public ExceptionEventArgs(string id,string info, Exception ex) { this._id = id; this._info = info; this._ex = ex; } private string _id; /// <summary> /// 获取文件信息保存在数据库中的Id /// </summary> public string Id { get { return _id; } } private string _info; /// <summary> /// 获取抛出异常的描述 /// </summary> public string Info { get { return _info; } } private Exception _ex; /// <summary> /// 抛出异常对象 /// </summary> public Exception Ex { get { return _ex; } } } }
using System; using System.Security.Cryptography; using System.IO; namespace Print.DownloadFile { public class MD5Lib { private static MD5 md5 = new MD5CryptoServiceProvider(); public MD5Lib() { } private static string MD5ByteToStr(byte[] b) { string result = ""; for (int i = 0; i < b.Length; i++) { result += b[i].ToString("X2"); } return result; } /// <summary> /// 取文件的MD5 /// </summary> /// <param name="fileName"></param> /// <returns></returns> public static string CalcFileMD5(string fileName) { Stream stream = File.OpenRead(fileName); return CalcStreamMD5(stream); } /// <summary> /// 取流的MD5 /// </summary> /// <param name="stream"></param> /// <returns></returns> public static string CalcStreamMD5(Stream stream) { byte[] md5Hash = md5.ComputeHash(stream); stream.Close(); return MD5ByteToStr(md5Hash); } /// <summary> /// 取字符串的MD5 /// </summary> /// <param name="str"></param> /// <returns></returns> public static string CalcStringMD5(string str) { byte[] source = System.Text.Encoding.Default.GetBytes(str); byte[] md5Hash = md5.ComputeHash(source); return MD5ByteToStr(md5Hash); } } }
using System; using System.Collections.Generic; using System.Text; namespace Print.DownloadFile { public class Util { #region<将文件大小转换成可读大小> /// <summary> /// 将文件的大小转换成可读的大小 /// </summary> /// <param name="lBytes"></param> /// <returns></returns> public static string HRSize(long lBytes) { StringBuilder sb = new StringBuilder(); string strUnits = "Bytes"; float fAdjusted = 0.0F; if (lBytes > 1024) { if (lBytes < 1024 * 1024) { strUnits = "KB"; fAdjusted = Convert.ToSingle(lBytes) / 1024; } else { strUnits = "MB"; fAdjusted = Convert.ToSingle(lBytes) / 1048576; } sb.AppendFormat("{0:0.0} {1}", fAdjusted, strUnits); } else { fAdjusted = Convert.ToSingle(lBytes); sb.AppendFormat("{0:0} {1}", fAdjusted, strUnits); } return sb.ToString(); } #endregion<结束文件大小的转换> } }
using System; using System.Collections.Generic; using System.Text; namespace Print.DownloadFile { public class ValidateMD5ErrorEventArgs :EventArgs { /// <summary> /// 构造方法 /// </summary> /// <param name="id">文件信息保存在数据库中的Id</param> /// <param name="availaMD5">用于验证文件有效的MD5</param> /// <param name="localFileMD5">文件下载完后本地的MD5</param> public ValidateMD5ErrorEventArgs(string id,string availaMD5, string localFileMD5) { this._availaMD5 = availaMD5; this._localFileMD5 = localFileMD5; this._id = id; } private string _id; /// <summary> /// 获取文件信息保存在数据库中的Id /// </summary> public string Id { get { return _id; } } private string _availaMD5; /// <summary> /// 获取有效的MD5值 /// </summary> public string AvailaMD5 { get { return _availaMD5; } } private string _localFileMD5; /// <summary> /// 获取下载完后本地的MD5值 /// </summary> public string LocalFileMD5 { get { return _localFileMD5; } } } }