You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
453 lines
12 KiB
C#
453 lines
12 KiB
C#
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 , "");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 下载URL资源到指定目录
|
|
/// </summary>
|
|
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();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 暂停
|
|
/// </summary>
|
|
public void Pause()
|
|
{
|
|
paused = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 继续
|
|
/// </summary>
|
|
public void Resume()
|
|
{
|
|
paused = false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 异步下载数据到当前目录
|
|
/// </summary>
|
|
public void AsyncDownload(string url)
|
|
{
|
|
System.Threading.ThreadPool.QueueUserWorkItem(
|
|
new System.Threading.WaitCallback(this.WaitCallbackMethod) , new string[] { url , "" });
|
|
}
|
|
|
|
/// <summary>
|
|
/// 异步下载数据到目标目录
|
|
/// </summary>
|
|
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);
|
|
}
|