using System; using System.IO; using System.Net; using System.Text; using System.Security; using System.Threading; using System.Collections.Specialized; using System.Diagnostics; using System.Data; namespace HttpDownload.DownloadFile ... { /**//// <summary> /// Download file info /// </summary> [Serializable()] public class DownloadFileInfo ...{ private string _requestURL; private string _responseURL; private string _fileName; private int _totalSize; private int _blockLeftSize; public string RequestURL ...{ get ...{ return _requestURL; } } public string ResponseURL ...{ get ...{ return _responseURL; } } public string FileName ...{ get ...{ return _fileName; } } public int TotalSize ...{ get ...{ return _totalSize; } set ...{ _totalSize = value; } } public int BlockLeftSize ...{ get ...{ return _blockLeftSize; } set ...{ _blockLeftSize = value; } } public DownloadFileInfo(string requestURL, string responseURL, string fileName, int totalSize, int blockLeftSize) ...{ this._requestURL = requestURL; this._responseURL = responseURL; this._fileName = fileName; this._totalSize = totalSize; this._blockLeftSize = blockLeftSize; } public DownloadFileInfo(string requestURL, string responseURL, string fileName) : this(requestURL, responseURL, fileName, 0, 0) ...{ } public DownloadFileInfo(string url, string fileName) : this(url, url, fileName, 0, 0) ...{ } private DownloadFileInfo() ...{ } public static DownloadFileInfo CreatFileInfo(DataRow drFileInfo) ...{ DownloadFileInfo newFileInfo = new DownloadFileInfo(); newFileInfo._requestURL = drFileInfo["RequestURL"].ToString(); newFileInfo._responseURL = drFileInfo["ResponseURL"].ToString(); newFileInfo._fileName = drFileInfo["FileName"].ToString(); newFileInfo._totalSize = Convert.ToInt32(drFileInfo["TotalSize"].ToString()); newFileInfo._blockLeftSize = Convert.ToInt32(drFileInfo["BlockLeftSize"].ToString()); return newFileInfo; } } /**//// <summary> /// Download event arguments /// </summary> public class DownLoadEventArgs : System.EventArgs ...{ private DownloadFileInfo _downloadFileInfo; private int _position; private int _readCount; private int _threadNO; public DownloadFileInfo DownFileInfo ...{ get ...{ return _downloadFileInfo; } } public int StartPosition ...{ get ...{ return _position; } } public int ReadCount ...{ get ...{ return _readCount; } } public int ThreadNO ...{ get ...{ return _threadNO; } } public DownLoadEventArgs(DownloadFileInfo DownFileInfo, int nStartPostion, int nReadCount, int nThreadNO) ...{ this._downloadFileInfo = DownFileInfo; this._position = nStartPostion; this._readCount = nReadCount; this._threadNO = nThreadNO; } } /**//// <summary> /// class for sub-download threads /// </summary> public class SubDownloadThread ...{ private int _threadNO; private int _position; private int _blockSizeLeft; private bool _isStopped; private Thread thdDownload; const int BUFFER_SIZE = 0x10000;//64k buffer size private readonly DownloadFileInfo _fileInfo; private EventHandler _finished; public event EventHandler<DownLoadEventArgs> DataReceived; public SubDownloadThread(DownloadFileInfo DownFileInfo, int ThreadNO, int Position, int BlockSizeLeft, EventHandler Finished) ...{ this._fileInfo = DownFileInfo; this._threadNO = ThreadNO; this._position = Position; this._blockSizeLeft = BlockSizeLeft; this._finished = Finished; } /**//// <summary> /// Start to create thread to download file /// </summary> public void StartDownload() ...{ thdDownload = new Thread(new ThreadStart(this.Download)); thdDownload.Start(); } /**//// <summary> /// Stop current download-thread /// </summary> public void Stop() ...{ _isStopped = true; if (thdDownload.ThreadState == System.Threading.ThreadState.Running) ...{ thdDownload.Join(10); } Debug.WriteLine(string.Format("Thread NO:{0} is stopped!", _threadNO)); } /**//// <summary> /// Function for sub-thread /// </summary> private void Download() ...{ HttpWebResponse hwrp = null; try ...{ Debug.WriteLine(string.Format("Thread NO:{0} begins to download!", _threadNO)); // Creat request by url HttpWebRequest hwrq = (HttpWebRequest)WebRequest.Create(new Uri(this._fileInfo.RequestURL)); // Go to download position hwrq.AddRange(_position); // Get response from request hwrp = (HttpWebResponse)hwrq.GetResponse(); } catch (Exception e) ...{ Debug.WriteLine(e.Message); return; } // download and write data from Debug.WriteLine(string.Format("Thread NO:{0} call function named DownloadData!", _threadNO)); DownloadData(hwrp); hwrp.Close();//Close response here } /**//// <summary> /// Download data through web request /// </summary> /// <param name="Response"></param> private void DownloadData(WebResponse Response) ...{ byte[] bBuffer = new byte[BUFFER_SIZE]; Stream sReader = Response.GetResponseStream(); if (sReader == null) return; int nReadCount = 0; while (!_isStopped && this._blockSizeLeft > 0) ...{ Debug.WriteLine(string.Format("Thread NO:{0} reads data!", _threadNO)); // Set read size nReadCount = (BUFFER_SIZE > this._blockSizeLeft) ? this._blockSizeLeft : BUFFER_SIZE;//Get current read count // Read data int nRealReadCount = sReader.Read(bBuffer, 0, nReadCount); if (nRealReadCount <= 0) break; Debug.WriteLine(string.Format("Thread NO:{0} writes data!", _threadNO)); // Write data using (FileStream sw = new FileStream(this._fileInfo.FileName + DownloadThread.filenameExt, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite, System.IO.FileShare.ReadWrite)) ...{ sw.Position = this._position; sw.Write(bBuffer, 0, nRealReadCount); Debug.WriteLine(string.Format("Thread NO:{0} writes {1} data!", _threadNO, nRealReadCount)); sw.Flush(); sw.Close(); } Debug.WriteLine(string.Format("Thread NO:{0} send callback info!", _threadNO)); // Call back EventHandler<DownLoadEventArgs> receivedHandler = DataReceived; if (receivedHandler != null) ...{ receivedHandler(this,new DownLoadEventArgs( this._fileInfo, this._position, nRealReadCount, this._threadNO)); } // Set position and block left this._position += nRealReadCount; this._blockSizeLeft -= nRealReadCount; } if (_isStopped) ...{ return; } Debug.WriteLine(string.Format("Thread NO:{0} sends finish-info!", _threadNO)); EventHandler finishHandle = _finished; if (finishHandle != null) ...{ finishHandle(this,EventArgs.Empty); } } } /**//// <summary> /// Class for download thread /// </summary> public class DownloadThread ...{ private DownloadFileInfo _fileInfo; private SubDownloadThread[] subThreads; private int nThreadFinishedCount; private DataRow drFileInfo; private DataTable dtThreadInfo; public EventHandler<DownLoadEventArgs> DataReceived; public event EventHandler Finished; public const string filenameExt = ".bf!"; //未下载完的扩展名 public DataTable ThreadInfo ...{ get ...{ return dtThreadInfo; } } /**//// Class's Constructor public DownloadThread(string requestURL, string responseURL, string fileName, DataRow newFileInfo, int subThreadNum) ...{ // Create download file info _fileInfo = new DownloadFileInfo(requestURL, responseURL, fileName); // Create request to get file info bool blnMultiDownload = GetFileDownInfo(); // Create file info datarow drFileInfo = newFileInfo; InitDataRow(); // Create subthreads and set these info in threadinfo table if (subThreadNum <= 0) subThreadNum = 5;//Defualt value //Not support to be multi-thread download or less than 64k if (!blnMultiDownload || _fileInfo.TotalSize <= 0x10000) subThreadNum = 1; subThreads = new SubDownloadThread[subThreadNum]; nThreadFinishedCount = 0; CreateThreadTable(subThreadNum); } public DownloadThread(string url, string fileName) : this(url, url, fileName, null, 2) ...{ } public DownloadThread(DataRow downloadFileInfo, DataTable threadInfos) ...{ // Create download file info drFileInfo = downloadFileInfo; _fileInfo = new DownloadFileInfo(drFileInfo["RequestURL"].ToString(), drFileInfo["ResponseURL"].ToString(), drFileInfo["FileName"].ToString(), Convert.ToInt32(drFileInfo["TotalSize"].ToString()), Convert.ToInt32(drFileInfo["BlockLeftSize"].ToString())); // Create sub thread class objects dtThreadInfo = threadInfos; subThreads = new SubDownloadThread[dtThreadInfo.Rows.Count]; nThreadFinishedCount = 0; } /**//// {Class's Constructor} /// <summary> /// Start to download /// </summary> public void Start() ...{ StartSubThreads(); } /**//// <summary> /// Create table to save thread info /// </summary> /// <param name="SubThreadNum"></param> private void CreateThreadTable(int SubThreadNum) ...{ int nThunkSize = _fileInfo.TotalSize / SubThreadNum; dtThreadInfo = new DataTable("DownloadFileInfo"); dtThreadInfo.Columns.Add("ThreadNO", typeof(int)); dtThreadInfo.Columns.Add("Position", typeof(int)); dtThreadInfo.Columns.Add("BlockLeftSize", typeof(int)); DataRow drNew; int i = 0; for (; i < SubThreadNum - 1; i++) ...{ drNew = dtThreadInfo.NewRow(); drNew["ThreadNO"] = i; drNew["Position"] = i * nThunkSize; drNew["BlockLeftSize"] = nThunkSize; dtThreadInfo.Rows.Add(drNew); } drNew = dtThreadInfo.NewRow(); drNew["ThreadNO"] = i; drNew["Position"] = i * nThunkSize; drNew["BlockLeftSize"] = _fileInfo.TotalSize - i * nThunkSize; dtThreadInfo.Rows.Add(drNew); dtThreadInfo.AcceptChanges(); } /**//// <summary> /// Start sub-threads to download file /// </summary> private void StartSubThreads() ...{ foreach (DataRow dr in dtThreadInfo.Rows) ...{ int ThreadNO = Convert.ToInt32(dr["ThreadNO"].ToString()); if (Convert.ToInt32(dr["BlockLeftSize"].ToString()) > 0) ...{ subThreads[ThreadNO] = new SubDownloadThread(_fileInfo, ThreadNO, Convert.ToInt32(dr["Position"].ToString()), Convert.ToInt32(dr["BlockLeftSize"].ToString()), new EventHandler(this.DownloadFinished)); subThreads[ThreadNO].DataReceived += this.DataReceived; subThreads[ThreadNO].StartDownload(); } else ...{ DownloadFinished(this,EventArgs.Empty); } } } /**//// <summary> /// Save download file info /// </summary> private void InitDataRow() ...{ if (drFileInfo != null) ...{ drFileInfo.BeginEdit(); drFileInfo["RequestURL"] = _fileInfo.RequestURL; drFileInfo["ResponseURL"] = _fileInfo.ResponseURL; drFileInfo["FileName"] = _fileInfo.FileName; drFileInfo["TotalSize"] = _fileInfo.TotalSize; drFileInfo["BlockLeftSize"] = _fileInfo.BlockLeftSize; drFileInfo["CreatedTime"] = DateTime.Now.ToString("yyyyMMddHHmmss"); drFileInfo.EndEdit(); drFileInfo.AcceptChanges(); } } /**//// <summary> /// Check url to get download file info /// </summary> /// <returns></returns> private bool GetFileDownInfo() ...{ HttpWebRequest hwrq; HttpWebResponse hwrp = null; try ...{ //Create request hwrq = (HttpWebRequest)WebRequest.Create(_fileInfo.RequestURL); hwrp = (HttpWebResponse)hwrq.GetResponse(); //Get file size info long L = hwrp.ContentLength; L = ((L == -1) || (L > 0x7fffffff)) ? ((long)0x7fffffff) : L; _fileInfo.TotalSize = (int)L; _fileInfo.BlockLeftSize = _fileInfo.TotalSize; //Check whether this url is supported to be multi-threads download bool blnMulti = (hwrp.Headers["Accept-Ranges"] != null && hwrp.Headers["Accept-Ranges"] == "bytes"); hwrp.Close();//Close response here return blnMulti; } catch (Exception e) ...{ throw e; } } /**//// <summary> /// Update download thread info /// </summary> /// <param name="ThreadNO"></param> /// <param name="Position"></param> /// <param name="DownloadSize"></param> public void UpdateDownloadInfo(int ThreadNO, int Position, int DownloadSize) ...{ if (ThreadNO >= dtThreadInfo.Rows.Count) ...{ return; } DataRow drThreadNO = dtThreadInfo.Rows[ThreadNO]; drThreadNO["Position"] = Position + DownloadSize; drThreadNO["BlockLeftSize"] = Convert.ToInt32(drThreadNO["BlockLeftSize"].ToString()) - DownloadSize; drThreadNO.AcceptChanges(); drFileInfo["BlockLeftSize"] = Convert.ToInt32(drFileInfo["BlockLeftSize"].ToString()) - DownloadSize; } /**//// <summary> /// Stop download threads /// </summary> public void Stop() ...{ for (int i = 0; i < subThreads.Length; i++) ...{ subThreads[i].Stop(); } } /**//// <summary> /// Thread download finished /// </summary> private void DownloadFinished(object sender,EventArgs e) ...{ // Some download thread finished nThreadFinishedCount++; if (nThreadFinishedCount == subThreads.Length) ...{ // All download threads finished if (drFileInfo != null) ...{ drFileInfo.Delete(); drFileInfo.AcceptChanges(); } File.Move(_fileInfo.FileName + filenameExt, GetNewFilename(_fileInfo.FileName)); EventHandler handler = Finished; if (handler != null) ...{ handler(this,EventArgs.Empty); } } } /**//// <summary> /// 得到新名称 /// </summary> /// <returns></returns> public static string GetNewFilename(string filename) ...{ if (File.Exists(filename)) ...{ string newname = filename; int i = 0; int lastPoint = filename.LastIndexOf('.'); do ...{ i++; if (lastPoint < 1) ...{ newname = filename + "(" + i + ")"; } else ...{ newname = filename.Substring(0, lastPoint) + "(" + i + ")" + filename.Substring(lastPoint); } } while (File.Exists(newname)); return newname; } else ...{ return filename; } } }}