Windows Store应用程序,使用线程下载多个文件

3
我有以下方法用于下载文件内容:
public async Task<String> DownloadFileService(String filePath, string id)
{
    string resposta = string.Empty;
    try
    {
        using (var httpClient = new HttpClient { BaseAddress = Constants.baseAddress })
        {
            string token = App.Current.Resources["token"] as string;
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

            string fname = Path.GetFileName(filePath);
            string path = Path.GetDirectoryName(filePath);
            path = path.Replace(fname, "");
            StorageFolder folder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(Constants.DataDirectory + "\\" + path, CreationCollisionOption.OpenIfExists);

            StorageFile imgFile = await folder.CreateFileAsync(fname, CreationCollisionOption.ReplaceExisting);

            using (var response2 = await httpClient.GetAsync("file?fileId=" + id))
            {

                Stream imageStream = await response2.Content.ReadAsStreamAsync();
                byte[] bytes = new byte[imageStream.Length];

                imageStream.Read(bytes, 0, (int)imageStream.Length);


                await FileIO.WriteBytesAsync(imgFile, bytes);
                resposta = Convert.ToBase64String(bytes);
            }

        }
        return resposta;
    }
    catch (Exception e)
    {
        Debug.WriteLine(e.Message);
    }
}

我想知道如何多次调用此方法以同时下载多个文件,并等待所有文件下载完成后再执行其他操作。
编辑
根据this的建议,我尝试创建了以下方法:
public async void checkFilesExist(JsonArray array, string path)
{
    List<Document> list = new List<Document>();
    ObjectsService obj = new ObjectsService();
    List<Task> ts = new List<Task>();

    foreach (var item in array)
    {
        JsonObject newDoc;
        JsonObject.TryParse(item.Stringify(), out newDoc);

        if (newDoc.ContainsKey("libraryType") || !newDoc.ContainsKey("fileName"))
            continue;
        string name = newDoc["fileName"].GetString();
        string id = newDoc["_id"].GetString();
        File file = new File(name);
        file.id = id;
        Document doc = file;
        doc.Parent = Document.FromPath(path);

        path = path.Replace("/", "\\");
        StorageFolder folder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(Constants.DataDirectory + "\\" + path, CreationCollisionOption.OpenIfExists);
        try
        {
            await folder.GetFileAsync(file.Name);
        }
        catch (Exception e)
        {
            list.Add(doc);
            Task x = obj.DownloadFileService(doc.GetFullPath(), file.id);
            ts.Add(x);
            Debug.WriteLine(" Ex: " + e.Message);
        }
    }
    try
    {
        Task.WaitAll(ts.ToArray());
        Debug.WriteLine("AFTER THrEADS");
    }
    catch (Exception e)
    {
        Debug.WriteLine("Ex2:  " + e.Message);
    }
}

这段代码的作用是,通过从 webservice 获取的带有 json 响应的文件列表,检查它们是否已经存在于本地文件夹中。如果不存在,则调用一开始提到的方法。
然后,我有一个任务列表,并将 DownloadFileService() 的调用作为新任务添加到列表中,之后我执行 Task.WaitAll() 等待下载完成。
使用 fiddler 我看到所有下载都开始了,但由于某种原因我的代码不会停留在 Task.WaitAll(),它会继续运行并开始使用仍在下载的文件,造成一系列问题:D

你尝试过调试你的代码吗?在 Task.WaitAll(ts.ToArray()); 这一行上打一个断点,看看代码是否到达那里。 - Hamid Pourjam
在某些断点处,我看到的行为大致如下:它会执行 await folder.GetFileAsync(file.Name); 然后执行 checkFilesExist 方法调用之后的代码,之后再进入 catch 块中的代码,这是在 folder.GetFileAsync(file.Name); 之后。 - Thought
好的,所以我将Task.WaitAll更改为await Task.WhenAll,现在似乎可以工作了。 - Thought
2个回答

4
你可以使用 Task.WaitAll。这个方法会等待所有提供的任务对象完成执行。
var t1 = DownloadFileService("file1", "1");
var t2 = DownloadFileService("file2", "2");
var t3 = DownloadFileService("file3", "3");

Tasks.WaitAll(t1, t2, t3);

1
或者你可以使用:

await  DownloadFileService("Path", "id");
await  DownloadFileService("Path", "id");
await  DownloadFileService("Path", "id");
await  DownloadFileService("Path", "id");

它如何等待它们全部完成? - Hamid Pourjam
由于 public async Task<String> DownloadFileService(String filePath, string id) 表示一个任务,所以没有问题,但如果问我框架是如何实现的,很抱歉我无法回答。 - Kevorkian
假设你想在所有任务完成后写下“完成”,你会怎么做? - Hamid Pourjam
需要从每个赋值中删除await,并将每个任务分配给一个变量,然后使用Tasks.WaitAll(var1, var2, var3, var4);否则,上面的代码将按顺序运行。 - Chris Ballance

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接