using System; using System.IO; using System.Net; namespace AutoUpdater { public class FileDownloader { private const int downloadBlockSize = 8192; private bool canceled = false; private bool paused = false; private string downloadingTo; public event DownloadProgressHandler ProgressChanged; public event DownloadProgressHandler StateChanged; public event EventHandler DownloadComplete; static string TEMP_DIR { get { string localTemp = System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData); localTemp = System.IO.Path.Combine(localTemp , "FileDownloader"); if (!Directory.Exists(localTemp)) Directory.CreateDirectory(localTemp); return localTemp; } } public static string DownloaderTempDirectory { get { return TEMP_DIR; } } public string DownloadingTo { get { return downloadingTo; } } public void Cancel() { this.canceled = true; } public FileDownloader() { } private void OnDownloadComplete() { if (this.DownloadComplete != null) this.DownloadComplete(this , new EventArgs()); } public void Download(string url) { Download(url , ""); } /// /// 下载URL资源到指定目录 /// public void Download(string url , string destFolder) { DownloadData data = null; this.canceled = false; try { if (canceled) return; if (destFolder != null & destFolder != string.Empty) { if (!Directory.Exists(Path.GetDirectoryName(destFolder))) Directory.CreateDirectory(Path.GetDirectoryName(destFolder)); } data = DownloadData.Create(url , destFolder); //string destFileName = Path.GetFileName(data.Response.ResponseUri.ToString()); string destFileName = Global.Instance.DownloadFileName; if (Path.GetDirectoryName(destFolder) == destFolder) this.downloadingTo = Path.GetFullPath(Path.Combine(destFolder , destFileName)); else this.downloadingTo = Path.GetDirectoryName(destFolder) + "\\" + destFileName;// destFolder; RaiseStateChanged(data.DownloadState); byte[] buffer = new byte[downloadBlockSize]; int readCount; long totalDownloaded = data.StartPoint; bool gotCanceled = false; while ((int)(readCount = data.DownloadStream.Read(buffer , 0 , downloadBlockSize)) > 0) { if (canceled) { gotCanceled = true; data.Close(); break; } while (paused) { System.Threading.Thread.Sleep(5); System.Windows.Forms.Application.DoEvents(); } totalDownloaded += readCount; SaveToFile(buffer , readCount , this.downloadingTo); if (data.IsProgressKnown) RaiseProgressChanged(totalDownloaded , data.FileSize); if (canceled) { gotCanceled = true; break; } } if (!gotCanceled) OnDownloadComplete(); } finally { if (data != null) data.Close(); } } /// /// 暂停 /// public void Pause() { paused = true; } /// /// 继续 /// public void Resume() { paused = false; } /// /// 异步下载数据到当前目录 /// public void AsyncDownload(string url) { System.Threading.ThreadPool.QueueUserWorkItem( new System.Threading.WaitCallback(this.WaitCallbackMethod) , new string[] { url , "" }); } /// /// 异步下载数据到目标目录 /// public void AsyncDownload(string url , string destFolder) { System.Threading.ThreadPool.QueueUserWorkItem( new System.Threading.WaitCallback(this.WaitCallbackMethod) , new string[] { url , destFolder }); } private void WaitCallbackMethod(object data) { String[] strings = data as String[]; this.Download(strings[0] , strings[1]); } private void RaiseStateChanged(string state) { if (this.StateChanged != null) this.StateChanged(this , new DownloadEventArgs(state)); } private void SaveToFile(byte[] buffer , int count , string fileName) { FileStream f = null; try { f = File.Open(fileName , FileMode.Append , FileAccess.Write); f.Write(buffer , 0 , count); } catch (ArgumentException e) { throw new ArgumentException(String.Format("尝试存储文件 \"{0}\": {1}" , fileName , e.Message) , e); } finally { if (f != null) f.Close(); } } private void RaiseProgressChanged(long current , long target) { if (this.ProgressChanged != null) this.ProgressChanged(this , new DownloadEventArgs(target , current)); } } public class DownloadData { private HttpWebResponse response; public HttpWebResponse Response { get { return response; } set { response = value; } } private Stream stream; private long size; private long start; private bool progressKnown; public static DownloadData Create(string url , string destFolder) { bool progressKnown; bool resume = false; long urlSize = GetFileSize(url , out progressKnown); long startPoint = 0; HttpWebRequest req = GetRequest(url); HttpWebResponse response; try { response = (HttpWebResponse)req.GetResponse(); } catch (Exception e) { throw new ArgumentException(String.Format( "下载错误 \"{0}\": {1}" , url , e.Message) , e); } if ((response.ContentType.IndexOf("text/html") > -1) || response.StatusCode == HttpStatusCode.NotFound) { throw new ArgumentException( String.Format("Couldn't download \"{0}\" - a web page was returned from the web server." , url)); } //String fileName = System.IO.Path.GetFileName(response.ResponseUri.ToString()); String fileName = Global.Instance.DownloadFileName; String downloadTo = string.Empty; if (Path.GetDirectoryName(destFolder) == destFolder) downloadTo = Path.GetFullPath(Path.Combine(destFolder , fileName)); else downloadTo = destFolder; if (progressKnown && File.Exists(downloadTo)) { startPoint = new FileInfo(downloadTo).Length; if (startPoint > urlSize) File.Delete(downloadTo); else if (startPoint < urlSize) { resume = true; req.AddRange((int)startPoint); } } else if (File.Exists(downloadTo)) File.Delete(downloadTo); if (resume) { response.Close(); req = GetRequest(url); req.AddRange((int)startPoint); response = (HttpWebResponse)req.GetResponse(); } if (resume && response.StatusCode != HttpStatusCode.PartialContent) { File.Delete(downloadTo); startPoint = 0; } return new DownloadData(response , urlSize , startPoint , progressKnown); } public static long GetFileSize(string url , out bool progressKnown) { HttpWebResponse response = null; long size = -1; try { response = (HttpWebResponse)GetRequest(url).GetResponse(); size = response.ContentLength; if (size == -1) progressKnown = false; else progressKnown = true; } finally { if (response != null) response.Close(); } return size; } private static HttpWebRequest GetRequest(string url) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Credentials = CredentialCache.DefaultCredentials; return request; } private DownloadData(HttpWebResponse response , long size , long start , bool progressKnown) { this.response = response; this.size = size; this.start = start; this.stream = null; this.progressKnown = progressKnown; } public Stream DownloadStream { get { if (this.start == this.size) return Stream.Null; if (this.stream == null) this.stream = this.response.GetResponseStream(); return this.stream; } } public long FileSize { get { return this.size; } } public long StartPoint { get { return this.start; } } public string DownloadState { get { return this.response.StatusCode.ToString(); } } public bool IsProgressKnown { get { return this.progressKnown; } } public void Close() { this.response.Close(); } } public class DownloadEventArgs : EventArgs { private int percentDone; private string downloadState; private long totalFileSize; public long TotalFileSize { get { return totalFileSize; } set { totalFileSize = value; } } private long currentFileSize; public long CurrentFileSize { get { return currentFileSize; } set { currentFileSize = value; } } public DownloadEventArgs(long totalFileSize , long currentFileSize) { this.totalFileSize = totalFileSize; this.currentFileSize = currentFileSize; this.percentDone = (int)((((double)currentFileSize) / totalFileSize) * 100); } public DownloadEventArgs(string state) { this.downloadState = state; } public DownloadEventArgs(int percentDone , string state) { this.percentDone = percentDone; this.downloadState = state; } public int PercentDone { get { return this.percentDone; } } public string DownloadState { get { return this.downloadState; } } } public delegate void DownloadProgressHandler(object sender , DownloadEventArgs e); }