给定 Uris 列表时,WebClient 不会下载所有文件
WebClient doesn't download all files when given a list of Uris
我正在制作一个工具,用于同时使用 List<Uri>
和 WebClient
class 从 Internet 下载图像。这是相关代码:
我正在使用的新 WebClient:
public class PatientWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri uri)
{
WebRequest w = base.GetWebRequest(uri);
w.Timeout = Timeout.Infinite;
return w;
}
}
及下载方式:
public static void DownloadFiles()
{
string filename = string.Empty;
while (_count < _images.Count())
{
PatientWebClient client = new PatientWebClient();
client.DownloadDataCompleted += DownloadCompleted;
filename = _images[_count].Segments.Last().ToString();
if (!File.Exists(_destinationFolder + @"\" + filename))
{
try
{
client.DownloadDataAsync(_images[_count], _images[_count]);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
++_count;
}
}
private static void DownloadCompleted(object sender, DownloadDataCompletedEventArgs e)
{
if (e.Error == null)
{
Uri uri = (Uri)e.UserState;
string saveFilename = uri.Segments.Last().ToString();
byte[] fileData = e.Result;
if (saveFilename.EndsWith(".jpg") || saveFilename.EndsWith(".png") || saveFilename.EndsWith(".gif"))
using (FileStream fileStream = new FileStream(_destinationFolder + @"\" + saveFilename, FileMode.Create))
fileStream.Write(fileData, 0, fileData.Length);
else
using (FileStream fileStream = new FileStream(_destinationFolder + @"\" + saveFilename + ".jpg", FileMode.Create))
fileStream.Write(fileData, 0, fileData.Length);
++_downloadedCounter;
((WebClient)sender).Dispose();
}
}
问题是并非列表 _images
中的所有图像都在下载。如果我第二次点击下载按钮,将会下载更多,实际上需要点击几下才能下载所有内容。 WebClient
是否超时,如果超时,是否有办法让它们自动重试下载?如果不是,解决这个问题的正确方法是什么?
我的意思是这样的,设置 webclient 超时并捕获错误:
internal class Program
{
private static void Main(string[] args)
{
Uri[] uris = {new Uri("http://www.google.com"), new Uri("http://www.yahoo.com")};
Parallel.ForEach(uris, uri =>
{
using (var webClient = new MyWebClient())
{
try
{
var data = webClient.DownloadData(uri);
// Success, do something with your data
}
catch (Exception ex)
{
// Something is wrong...
Console.WriteLine(ex.ToString());
}
}
});
}
}
public class MyWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri uri)
{
var w = base.GetWebRequest(uri);
w.Timeout = 5000; // 5 seconds timeout
return w;
}
}
如果你仍然想使用那个模式,这个模式没有超时,你必须使用定时器来实现:
internal class Program
{
private static int _downloadCounter;
private static readonly object _syncObj = new object();
private static void Main(string[] args)
{
Uri[] uris = {new Uri("http://www.google.com"), new Uri("http://www.yahoo.com")};
foreach (var uri in uris)
{
var webClient = new WebClient();
webClient.DownloadDataCompleted += OnWebClientDownloadDataCompleted;
webClient.DownloadDataAsync(uri);
}
Thread.Sleep(Timeout.Infinite);
}
private static void OnWebClientDownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
if (e.Error == null)
{
// OK
Console.WriteLine(Encoding.UTF8.GetString(e.Result));
}
else
{
// Error
Console.WriteLine(e.Error.ToString());
}
lock (_syncObj)
{
_downloadCounter++;
Console.WriteLine("Counter = {0}", _downloadCounter);
}
var webClient = sender as WebClient;
if (webClient == null) return;
webClient.DownloadDataCompleted -= OnWebClientDownloadDataCompleted;
webClient.Dispose();
}
}
我正在制作一个工具,用于同时使用 List<Uri>
和 WebClient
class 从 Internet 下载图像。这是相关代码:
我正在使用的新 WebClient:
public class PatientWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri uri)
{
WebRequest w = base.GetWebRequest(uri);
w.Timeout = Timeout.Infinite;
return w;
}
}
及下载方式:
public static void DownloadFiles()
{
string filename = string.Empty;
while (_count < _images.Count())
{
PatientWebClient client = new PatientWebClient();
client.DownloadDataCompleted += DownloadCompleted;
filename = _images[_count].Segments.Last().ToString();
if (!File.Exists(_destinationFolder + @"\" + filename))
{
try
{
client.DownloadDataAsync(_images[_count], _images[_count]);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
++_count;
}
}
private static void DownloadCompleted(object sender, DownloadDataCompletedEventArgs e)
{
if (e.Error == null)
{
Uri uri = (Uri)e.UserState;
string saveFilename = uri.Segments.Last().ToString();
byte[] fileData = e.Result;
if (saveFilename.EndsWith(".jpg") || saveFilename.EndsWith(".png") || saveFilename.EndsWith(".gif"))
using (FileStream fileStream = new FileStream(_destinationFolder + @"\" + saveFilename, FileMode.Create))
fileStream.Write(fileData, 0, fileData.Length);
else
using (FileStream fileStream = new FileStream(_destinationFolder + @"\" + saveFilename + ".jpg", FileMode.Create))
fileStream.Write(fileData, 0, fileData.Length);
++_downloadedCounter;
((WebClient)sender).Dispose();
}
}
问题是并非列表 _images
中的所有图像都在下载。如果我第二次点击下载按钮,将会下载更多,实际上需要点击几下才能下载所有内容。 WebClient
是否超时,如果超时,是否有办法让它们自动重试下载?如果不是,解决这个问题的正确方法是什么?
我的意思是这样的,设置 webclient 超时并捕获错误:
internal class Program
{
private static void Main(string[] args)
{
Uri[] uris = {new Uri("http://www.google.com"), new Uri("http://www.yahoo.com")};
Parallel.ForEach(uris, uri =>
{
using (var webClient = new MyWebClient())
{
try
{
var data = webClient.DownloadData(uri);
// Success, do something with your data
}
catch (Exception ex)
{
// Something is wrong...
Console.WriteLine(ex.ToString());
}
}
});
}
}
public class MyWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri uri)
{
var w = base.GetWebRequest(uri);
w.Timeout = 5000; // 5 seconds timeout
return w;
}
}
如果你仍然想使用那个模式,这个模式没有超时,你必须使用定时器来实现:
internal class Program
{
private static int _downloadCounter;
private static readonly object _syncObj = new object();
private static void Main(string[] args)
{
Uri[] uris = {new Uri("http://www.google.com"), new Uri("http://www.yahoo.com")};
foreach (var uri in uris)
{
var webClient = new WebClient();
webClient.DownloadDataCompleted += OnWebClientDownloadDataCompleted;
webClient.DownloadDataAsync(uri);
}
Thread.Sleep(Timeout.Infinite);
}
private static void OnWebClientDownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
if (e.Error == null)
{
// OK
Console.WriteLine(Encoding.UTF8.GetString(e.Result));
}
else
{
// Error
Console.WriteLine(e.Error.ToString());
}
lock (_syncObj)
{
_downloadCounter++;
Console.WriteLine("Counter = {0}", _downloadCounter);
}
var webClient = sender as WebClient;
if (webClient == null) return;
webClient.DownloadDataCompleted -= OnWebClientDownloadDataCompleted;
webClient.Dispose();
}
}