我刚写了一个下载管理器来并行下载多个文件。但我有这个脚本的1个问题,我找不到答案。经过很多文件(100会做)。有时线程只是没有完成它的工作。它不会触发超时,也不会触发我放置的异常或控制台日志。当我检查需要下载所有文件的文件夹时,我在那里看到一个不完整的文件,它正被应用程序使用(我知道这是因为我关闭应用程序之前无法删除文件)。我希望有人会在我的剧本中看到问题。
//Download complete delegate
public delegate void DownloadCompleteHandler(DownloadableObject source, DownloadCompletedEventArgs e);
//Download complete event args
public class DownloadCompletedEventArgs : EventArgs
{
private string EventInfo;
public DownloadCompletedEventArgs(string text)
{
EventInfo = text;
}
public string GetInfo()
{
return EventInfo;
}
}
class DownloadManager
{
//Downloadcomplete Handler
public event DownloadCompleteHandler DownloadComplete;
//The amount of downloads that can run in parallel
public int parallelDownloads = 1;
//All the downloads in a list
public List<DownloadableObject> downloads = new List<DownloadableObject>();
public DownloadManager(int parallelDownloads = 1)
{
this.parallelDownloads = parallelDownloads;
}
//This adds a download to the list.
public void addDownload(string url, string saveLocation)
{
DownloadableObject dl = new DownloadableObject() { url = url, saveLocation = saveLocation };
downloads.Add(dl);
}
//This starts the parallel downloader
public void startParallelDownloads()
{
for(int i = 0; i < parallelDownloads; i++)
{
startDownload();
}
}
//This starts a single download Async
private void startDownload()
{
//Check if the downloads list contains anything
if(downloads.Any())
{
//Get the first download from the list and remove it so it doesn't get downloaded again.
DownloadableObject currentDl = downloads[0];
downloads.RemoveAt(0);
//Setup a webrequest.
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(currentDl.url);
webRequest.Method = "GET";
webRequest.Timeout = 4000;
currentDl.webRequest = webRequest;
IAsyncResult result = webRequest.BeginGetResponse(new AsyncCallback(downloadResponse), currentDl);
//This handles the timeout response
ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(timeoutCallback), currentDl, currentDl.webRequest.Timeout, true);
} else
{
//Called when a Thread is done downloading. This should be called when the download list is empty
Console.WriteLine("THREAD DONE!");
}
}
//This is the callback when a timeout occurs
private void timeoutCallback(object state, bool timedOut)
{
if(timedOut)
{
//Get the timedout request
HttpWebRequest request = ((DownloadableObject)state).webRequest;
if(request != null)
{
Console.WriteLine("Too Bad!");
//And abort it
request.Abort();
//Set the webrequest in the downloadable object to null and add it to the download list again so it will be downloaded again
((DownloadableObject)state).webRequest = null;
downloads.Add(((DownloadableObject)state));
//Refire the thread.
startDownload();
}
}
}
private void downloadResponse(IAsyncResult asyncResult)
{
int received = 0;
//Get the current download from the asyncResult.
DownloadableObject currentDl = (DownloadableObject)asyncResult.AsyncState;
try
{
using (HttpWebResponse webResponse = (HttpWebResponse)currentDl.webRequest.EndGetResponse(asyncResult))
{
byte[] buffer = new byte[1024];
//Creates a file in the correct location.
FileStream fileStream = File.OpenWrite(currentDl.saveLocation);
using (Stream input = webResponse.GetResponseStream())
{
//Write data to the buffer.
int size = input.Read(buffer, 0, buffer.Length);
while (size > 0)
{
fileStream.Write(buffer, 0, size);
received += size;
size = input.Read(buffer, 0, buffer.Length);
}
}
//Write data to the file and close it.
fileStream.Flush();
fileStream.Close();
//Call the download complete event
DownloadComplete(currentDl, new DownloadCompletedEventArgs("Download completed"));
//refire the Thread again.
startDownload();
}
}
catch (WebException e)
{
}
}
}
//A downloadable object.
public class DownloadableObject
{
//Url to file to download
public string url { get; set; }
//Location where to save the file
public string saveLocation { get; set; }
//The webrequest that is assigned to this download. This will be null when the download list is filled.
public HttpWebRequest webRequest { get; set; }
}