我有一个zip文件创建者,它接收String[]
个Urls,并返回一个包含String[]
我认为会有很多这方面的例子,但我似乎无法找到答案"如何异步下载多个文件并在完成后返回"
如何一次下载{n}个文件,并且仅在所有下载完成后返回词典?
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);
}
答案 0 :(得分:5)
async-await
标记了您的问题,但未实际使用它。没有理由再使用旧的异步范例了。 async
操作,您应该使用Task.WhenAll
,这意味着您需要在某些构造(即字典)中保留所有任务实际上提取他们的结果。uri
解析为文件名,然后从async
任务中提取结果,即可创建新的结果字典。 / LI>
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);
}
答案 1 :(得分:0)
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;
}
答案 2 :(得分:-1)
你想要这个任务。等待所有方法......
将每个下载创建为单独的任务,然后将它们作为集合传递。
此快捷方式可能是将下载方法包装在任务中。
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;
});
}
在转换回IDictionary之前,它利用并发集合来支持方法中的并行访问。
此方法返回一个任务,因此可以使用await调用。
希望这提供了一个有用的选择。