【问题标题】:Wait till the last file is downloaded等到最后一个文件下载完毕
【发布时间】:2020-01-09 08:31:33
【问题描述】:

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

进程无法访问该文件,因为它正被另一个进程使用 过程。

如何确保文件被下载?

            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);
            }


        }


    }

}

【问题讨论】:

  • Downloads, to a local file, the resource with the specified URI. This method does not block the calling thread. 根据 MS docthis以前的帖子应该对你有帮助
  • 旁注:现在是 2020 年......使用 awaitWhenAll 编写和管理回调要容易得多......
  • 这能回答你的问题吗? DownloadFile vs DownloadFileAsync

标签: c# web-scraping web-crawler html-agility-pack


【解决方案1】:

您当然不想使用WebClient.DownloadFileAsync,而是使用它的新继任者WebClient.DownloadFileTaskAsync。这将像这样使用:

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

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

【讨论】:

  • 嗯...谢谢你,但现在它说'WebClient' does not contain a definition for 'DownloadFileAsyncTask' and no accessible extension method 'DownloadFileAsyncTask' accepting a first argument of type 'WebClient' could be found
  • 哦,我打错字了:应该是 DownloadFileTaskAsync 而不是 DownloadFileAsyncTask。会更新。
  • 我在“项目属性 -> 应用程序选项卡”中的项目显示目标框架:.NET Framework 4.7.2
  • 是的,没关系 - 我的回答有误。现在是正确的。
  • 太棒了!现在它起作用了!也许你对这个问题有一些想法?我以某种方式认为 async/await 将有助于加载页面以获取 ProductListPage。例如,我注意到 VPN 连接页面在 Chrome 中的加载有一点延迟。所以第一页被加载,然后是内容。也许这是错误的原因? stackoverflow.com/questions/59628313/…
【解决方案2】:

您应该异步加载和下载它,而不是阻塞当前线程。当你这样做时,它会将线程释放给调用者并仅在加载/下载完成时返回到上下文

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多