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方法>
}
}