等到最后一个文件下载完毕

Wait till the last file is downloaded

我有一个下载 PDF 文件的代码。现在,当我执行下一个任务但最后一个文件的下载尚未完成时,我遇到了 运行 问题。执行完我当前的代码后,最后一个文件大约是 650 Mb,应该是 1300 Mb。也无法打开它,因为它没有完全下载,这就是损坏的原因。

The process cannot access the file because it is being used by another process.

如何保证文件下载成功?

            HtmlDocument htmlDoc = new HtmlWeb().Load("http://example.com/");

            // Thread.Sleep(5000); // wait some time

            HtmlNodeCollection ProductListPage = htmlDoc.DocumentNode.SelectNodes("//div[@class='productContain padb6']//div[@class='large-4 medium-4 columns']/a");
            foreach (HtmlNode src in ProductListPage)
            {
                htmlDoc = new HtmlWeb().Load(src.Attributes["href"].Value);

                // Thread.Sleep(5000); // wait some time

                HtmlNodeCollection LinkTester = htmlDoc.DocumentNode.SelectNodes("//div[@class='row padt6 padb4']//a");
                if (LinkTester != null)
                {
                    foreach (var dllink in LinkTester)
                    {
                        string LinkURL = dllink.Attributes["href"].Value;
                        Console.WriteLine(LinkURL);

                        string ExtractFilename = LinkURL.Substring(LinkURL.LastIndexOf("/"));
                        var DLClient = new WebClient();

                        // Thread.Sleep(5000); // wait some time

                        DLClient.DownloadFileAsync(new Uri(LinkURL), @"C:\temp\" + ExtractFilename);
                    }
                }
            }

我的下一个过程是重命名下载的文件:

    var files = Directory.GetFiles(@"C:\temp\", "*.pdf");
    // string prefix = "SomePrefix";
    foreach (var file in files)
    {
        string newFileName = Path.Combine(Path.GetDirectoryName(file), file.Replace("-", " "));
        File.Move(file, newFileName);
    }

重命名很顺利,直到最后一个文件未完全下载,这就是我遇到错误的地方。

我在这两者之间添加了 Thread.Sleep(5000); // wait some time,但这可能不是最好的解决方案,因为当前的等待时间不够,并且它会根据互联网连接而改变?

完整代码如下:

using System;
using System.Net;
using HtmlAgilityPack;
using System.IO;
using System.Threading;


namespace Crawler
{

    class Program
    {
        static void Main(string[] args)
        {

            {
                HtmlDocument htmlDoc = new HtmlWeb().Load("http://example.com");

                // Thread.Sleep(5000); // wait some time

                HtmlNodeCollection ProductListPage = htmlDoc.DocumentNode.SelectNodes("//div[@class='productContain padb6']//div[@class='large-4 medium-4 columns']/a");
                foreach (HtmlNode src in ProductListPage)
                {
                    htmlDoc = new HtmlWeb().Load(src.Attributes["href"].Value);

                    // Thread.Sleep(5000); // wait some time

                    HtmlNodeCollection LinkTester = htmlDoc.DocumentNode.SelectNodes("//div[@class='row padt6 padb4']//a");
                    if (LinkTester != null)
                    {
                        foreach (var dllink in LinkTester)
                        {
                            string LinkURL = dllink.Attributes["href"].Value;
                            Console.WriteLine(LinkURL);

                            string ExtractFilename = LinkURL.Substring(LinkURL.LastIndexOf("/"));
                            var DLClient = new WebClient();

                            // Thread.Sleep(5000); // wait some time

                            DLClient.DownloadFileAsync(new Uri(LinkURL), @"C:\temp\" + ExtractFilename);
                        }
                    }
                }
            }

            Thread.Sleep(5000); // wait some time

            var files = Directory.GetFiles(@"C:\temp\", "*.pdf");
            // string prefix = "SomePrefix";
            foreach (var file in files)
            {
                string newFileName = Path.Combine(Path.GetDirectoryName(file), file.Replace("-", " "));
                File.Move(file, newFileName);
            }


        }


    }

}

您肯定不想使用 WebClient.DownloadFileAsync,而是它的更新后继者 WebClient.DownloadFileTaskAsync。这将像这样使用:

await DLClient.DownloadFileTaskAsync(new Uri(LinkURL), @"C:\temp\" + ExtractFilename);

这是一个 async 过程,因此您的调用方法也需要是 async。通过 awaiting 它,您可以确保您的程序仅在下载完成(或下载失败)后继续。

您应该异步加载和下载它,而不是阻塞当前线程。当您执行此操作时,它会将线程释放给调用者,并且 return 仅在 Load/DownLoad 完成时才返回上下文

 htmlDoc = await new HtmlWeb().LoadAsync(src.Attributes["href"].Value);

 await DLClient.DownloadFileAsync(new Uri(LinkURL), @"C:\temp\" + ExtractFilename);