问题
I'm writing a very simple bulk download program in c# that reads a .txt file of URLs to download. I've set it up with a global Thread and delegate for updating the GUI, and the pressing of the "Begin" button creates and starts that thread. What I want to do is have a "Pause" button that enables me to pause the download until I hit the "Resume" button. How do I do this?
The relevant code:
private Thread thr;
private delegate void UpdateProgressCallback(int curFile);
private void Begin_btn_Click(object sender, EventArgs e)
{
thr = new Thread(Download);
thr.Start();
}
private void Pause_btn_Click(object sender, EventArgs e)
{
Pause_btn.Visible = false;
Resume_btn.Visible = true;
//{PAUSE THREAD thr}
}
private void Resume_btn_Click(object sender, Eventargs e)
{
Pause_btn.Visible = true;
Resume_btn.Visible = false;
//{RESUME THREAD thr}
}
public void Download()
{
//Download code goes here
}
Obviously, I am NOT using a Worker, and I really don't wish to unless you can show me how to get it to work (I don't really understand workers). Any help would be appreciated.
回答1:
If you use System.Net.WebClient.DownloadFile()
or System.Net.WebClient.DownloadFileAsync()
method then you cannot pause the download. The difference between these methods is that the latter method will start an asynchronous download so you will not need to create a separate thread yourself if you use this method. Unfortunately, downloads executed with either method cannot be paused or resumed.
You need to use System.Net.HttpWebRequest
. Try something like this:
class Downloader
{
private const int chunkSize = 1024;
private bool doDownload = true;
private string url;
private string filename;
private Thread downloadThread;
public long FileSize
{
get;
private set;
}
public long Progress
{
get;
private set;
}
public Downloader(string Url, string Filename)
{
this.url = Url;
this.filename = Filename;
}
public void StartDownload()
{
Progress = 0;
FileSize = 0;
commenceDownload();
}
public void PauseDownload()
{
doDownload = false;
downloadThread.Join();
}
public void ResumeDownload()
{
doDownload = true;
commenceDownload();
}
private void commenceDownload()
{
downloadThread = new Thread(downloadWorker);
downloadThread.Start();
}
public void downloadWorker()
{
// Creates an HttpWebRequest with the specified URL.
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);
FileMode filemode;
// For download resume
if (Progress == 0)
{
filemode = FileMode.CreateNew;
}
else
{
filemode = FileMode.Append;
myHttpWebRequest.AddRange(Progress);
}
// Set up a filestream to write the file
// Sends the HttpWebRequest and waits for the response.
using (FileStream fs = new FileStream(filename, filemode))
using (HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse())
{
// Gets the stream associated with the response.
Stream receiveStream = myHttpWebResponse.GetResponseStream();
FileSize = myHttpWebResponse.ContentLength;
byte[] read = new byte[chunkSize];
int count;
while ((count = receiveStream.Read(read, 0, chunkSize)) > 0 && doDownload)
{
fs.Write(read, 0, count);
count = receiveStream.Read(read, 0, chunkSize);
Progress += count;
}
}
}
}
I used some code from HttpWebRequest.GetResponse page on MSDN.
Instead of stopping the thread on Pause and starting a new one on Resume, you can also change the while
loop to wait until download is resumed as following:
while ((count = receiveStream.Read(read, 0, chunkSize)) > 0)
{
fs.Write(read, 0, count);
count = receiveStream.Read(read, 0, chunkSize);
Progress += count;
while(!doDownload)
System.Threading.Thread.Sleep(100);
}
The up-side is that you may be able to re-use the same thread. The down-side is that the connection may timeout and become closed. In the latter case, you will need to detect this and re-connect.
You may also want to add an event for when the donwload is completed.
来源:https://stackoverflow.com/questions/7060348/pausing-a-download-thread