使用DownloadDataAsync等待多个文件下载
本文关键字:文件下载 等待 DownloadDataAsync 使用 | 更新日期: 2023-09-27 18:18:38
我有一个zip文件创建器,它接受url的String[]
,并返回一个包含String[]
中所有文件的zip文件
我想会有一些这样的例子,但我似乎找不到一个答案"如何异步下载许多文件,并在完成时返回"
如何一次性下载{n}文件,并在所有下载完成后才返回Dictionary ?
private static Dictionary<string, byte[]> ReturnedFileData(IEnumerable<string> urlList)
{
var returnList = new Dictionary<string, byte[]>();
using (var client = new WebClient())
{
foreach (var url in urlList)
{
client.DownloadDataCompleted += (sender1, e1) => returnList.Add(GetFileNameFromUrlString(url), e1.Result);
client.DownloadDataAsync(new Uri(url));
}
}
return returnList;
}
private static string GetFileNameFromUrlString(string url)
{
var uri = new Uri(url);
return System.IO.Path.GetFileName(uri.LocalPath);
}
- 首先,你用
- 等待异步为所有并发
async
操作完成,你应该使用Task.WhenAll
,这意味着你需要保持所有的任务在一些结构(即字典)之前实际提取他们的结果。 - 最后,当您拥有所有结果时,只需通过解析
uri
到文件名来创建新的结果字典,并从async
任务中提取结果。
async-await
标记了你的问题,而没有实际使用它。真的没有理由再使用旧的异步范例了。async Task<Dictionary<string, byte[]>> ReturnFileData(IEnumerable<string> urls)
{
var dictionary = urls.ToDictionary(
url => new Uri(url),
url => new WebClient().DownloadDataTaskAsync(url));
await Task.WhenAll(dictionary.Values);
return dictionary.ToDictionary(
pair => Path.GetFileName(pair.Key.LocalPath),
pair => pair.Value.Result);
}
public string JUST_return_dataURL_by_URL(string URL, int interval, int max_interval)
{
var client = new WebClient(proxy);
client.Headers = _headers;
string downloaded_from_URL = "false"; //default - until downloading
client.DownloadDataCompleted += bytes =>
{
Console.WriteLine("Done!");
string dataURL = Convert.ToBase64String( bytes );
string filename = Guid.NewGuid().ToString().Trim('{', '}')+".png";
downloaded_from_URL =
"Image Downloaded from " + URL
+ "<br>"
+ "<a href='""+dataURL+"'" download='""+filename+"'">"
+ "<img src='"data:image/png;base64," + dataURL + "'"/>"+filename
+ "</a>"
;
return;
};
client.DownloadDataAsync(new System.Uri(URL));
int i = 0;
do{
// Console.WriteLine(
// "(interval > 10): "+(interval > 10)
// +"'n(downloaded_from_URL == '"false'"): " + (downloaded_from_URL == "false")
// +"'ninterval: "+interval
// );
Thread.Sleep(interval);
i+=interval;
}
while( (downloaded_from_URL == "false") && (i < max_interval) );
return downloaded_from_URL;
}
你想要这个任务。WaitAll方法…
msdn联系
将每个下载创建为单独的任务,然后将它们作为集合传递。
快捷方式可能是将下载方法包装在任务中。
Return new Task<downloadresult>(()=>{ method body});
为模糊道歉,在iPad上工作太糟糕了。
编辑:另一个值得考虑的实现是使用并行框架包装下载。
因为你的任务都做同样的事情接受一个参数,你可以用Parallel代替。Foreach并将其封装到单个任务中:
public System.Threading.Tasks.Task<System.Collections.Generic.IDictionary<string, byte[]>> DownloadTask(System.Collections.Generic.IEnumerable<string> urlList)
{
return new System.Threading.Tasks.Task<System.Collections.Generic.IDictionary<string, byte[]>>(() =>
{
var r = new System.Collections.Concurrent.ConcurrentDictionary<string, byte[]>();
System.Threading.Tasks.Parallel.ForEach<string>(urlList, (url, s, l) =>
{
using (System.Net.WebClient client = new System.Net.WebClient())
{
var bytedata = client.DownloadData(url);
r.TryAdd(url, bytedata);
}
});
var results = new System.Collections.Generic.Dictionary<string, byte[]>();
foreach (var value in r)
{
results.Add(value.Key, value.Value);
}
return results;
});
}
在转换回字典之前,它利用并发集合来支持方法内的并行访问。
此方法返回一个任务,因此可以通过await调用。