【问题标题】:How to check if System.Net.WebClient.DownloadData is downloading a binary file?如何检查 System.Net.WebClient.DownloadData 是否正在下载二进制文件?
【发布时间】:2010-09-14 06:50:08
【问题描述】:

我正在尝试使用WebClient 通过 WinForms 应用程序从 Web 下载文件。但是,我真的只想下载 HTML 文件。我想忽略的任何其他类型。

我检查了WebResponse.ContentType,但它的值始终是null

有人知道可能是什么原因吗?

【问题讨论】:

  • 你想要图片、样式表和 JavaScript 吗?

标签: c# file download webclient


【解决方案1】:

您可以使用 HEAD 动词发出第一个请求,并检查内容类型响应标头吗? [编辑] 不过,看起来您必须为此使用 HttpWebRequest。

【讨论】:

  • (已被 OP 的后续行动淘汰 - 请参阅我关于 GetWebRequest 的其他回复)
【解决方案2】:

WebResponse 是一个抽象类,ContentType 属性是在继承类中定义的。例如,在 HttpWebRequest 对象中,此方法被重载以提供内容类型标头。我不确定 WebClient 使用的是哪个 WebResponse 实例。如果你只想要 HTML 文件,最好直接使用 HttpWebRequest 对象。

【讨论】:

    【解决方案3】:

    您的问题有点令人困惑:如果您使用的是 Net.WebClient 类的实例,则 Net.WebResponse 不会进入等式(除了它确实是一个抽象类,而且您d 正在使用具体的实现,例如 HttpWebResponse,正如另一个响应中指出的那样)。

    无论如何,在使用 WebClient 时,您可以通过执行以下操作来实现您想要的:

    Dim wc As New Net.WebClient()
    Dim LocalFile As String = IO.Path.Combine(Environment.GetEnvironmentVariable("TEMP"), Guid.NewGuid.ToString)
    wc.DownloadFile("http://example.com/somefile", LocalFile)
    If Not wc.ResponseHeaders("Content-Type") Is Nothing AndAlso wc.ResponseHeaders("Content-Type") <> "text/html" Then
        IO.File.Delete(LocalFile)
    Else
        '//Process the file
    End If
    

    请注意,您必须检查 Content-Type 标头是否存在,因为服务器不保证会返回它(尽管大多数现代 HTTP 服务器将始终包含它)。如果没有 Content-Type 标头,您可以退回到另一种 HTML 检测方法,例如打开文件,将前 1K 字符左右读入字符串,然后查看其中是否包含子字符串

    另请注意,这有点浪费,因为在决定是否需要之前,您总是会传输完整的文件。要解决这个问题,切换到 Net.HttpWebRequest/Response 类可能会有所帮助,但额外代码是否值得取决于您的应用程序...

    【讨论】:

      【解决方案4】:

      我很抱歉没有很清楚。我编写了一个扩展 WebClient 的包装类。在这个包装类中,我添加了 cookie 容器并公开了 WebRequest 的 timeout 属性。

      我正在使用此包装类中的 DownloadDataAsync(),但无法从此包装类的 WebResponse 中检索内容类型。我的主要目的是拦截响应并确定其是否为 text/html 性质。如果不是,我将中止此请求。

      在覆盖 WebClient.GetWebResponse(WebRequest, IAsyncResult) 方法后,我设法获得了内容类型。

      以下是我的包装类的示例:

      public class MyWebClient : WebClient
      {
          private CookieContainer _cookieContainer;
          private string _userAgent;
          private int _timeout;
          private WebReponse _response;
      
          public MyWebClient()
          {
              this._cookieContainer = new CookieContainer();
              this.SetTimeout(60 * 1000);
          }
      
          public MyWebClient SetTimeout(int timeout)
          {
              this.Timeout = timeout;
              return this;
          }
      
          public WebResponse Response
          {
              get { return this._response; }
          }
      
          protected override WebRequest GetWebRequest(Uri address)
          {
              WebRequest request = base.GetWebRequest(address);
      
              if (request.GetType() == typeof(HttpWebRequest))
              {
                  ((HttpWebRequest)request).CookieContainer = this._cookieContainer;
                  ((HttpWebRequest)request).UserAgent = this._userAgent;
                  ((HttpWebRequest)request).Timeout = this._timeout;
              }
      
              this._request = request;
              return request;
          }
      
          protected override WebResponse GetWebResponse(WebRequest request)
          {
              this._response = base.GetWebResponse(request);
              return this._response;
          }
      
          protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result)
          {
              this._response = base.GetWebResponse(request, result);
              return this._response;
          }
      
          public MyWebClient ServerCertValidation(bool validate)
          {
              if (!validate) ServicePointManager.ServerCertificateValidationCallback += delegate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
              return this;
          }
      }
      

      【讨论】:

      • 在这种情况下,更改 .Method - 请参阅我的其他回复。
      【解决方案5】:

      鉴于您的更新,您可以通过更改 GetWebRequest 中的 .Method 来做到这一点:

      using System;
      using System.Net;
      static class Program
      {
          static void Main()
          {
              using (MyClient client = new MyClient())
              {
                  client.HeadOnly = true;
                  string uri = "http://www.google.com";
                  byte[] body = client.DownloadData(uri); // note should be 0-length
                  string type = client.ResponseHeaders["content-type"];
                  client.HeadOnly = false;
                  // check 'tis not binary... we'll use text/, but could
                  // check for text/html
                  if (type.StartsWith(@"text/"))
                  {
                      string text = client.DownloadString(uri);
                      Console.WriteLine(text);
                  }
              }
          }
      
      }
      
      class MyClient : WebClient
      {
          public bool HeadOnly { get; set; }
          protected override WebRequest GetWebRequest(Uri address)
          {
              WebRequest req = base.GetWebRequest(address);
              if (HeadOnly && req.Method == "GET")
              {
                  req.Method = "HEAD";
              }
              return req;
          }
      }
      

      或者,您可以在覆盖 GetWebRespons() 时检查标头,如果不是您想要的,可能会引发异常:

      protected override WebResponse GetWebResponse(WebRequest request)
      {
          WebResponse resp = base.GetWebResponse(request);
          string type = resp.Headers["content-type"];
          // do something with type
          return resp;
      }
      

      【讨论】:

      【解决方案6】:

      我不确定原因,但也许你还没有下载任何东西。这是获取远程文件/页面内容类型的懒惰方式(我没有检查这是否在线上有效。据我所知,它可能会下载大量内容)

              Stream connection = new MemoryStream(""); // Just a placeholder
              WebClient wc = new WebClient();
              string contentType;
              try
              {
                  connection = wc.OpenRead(current.Url);
                  contentType = wc.ResponseHeaders["content-type"];
              }
              catch (Exception)
              {
                  // 404 or what have you
              }
              finally
              {
                  connection.Close();
              }
      

      【讨论】:

        【解决方案7】:

        这是一种使用 TCP 的方法,http 是建立在它之上的。它会在连接时或超时(毫秒)后返回,因此可能需要根据您的情况更改该值

        var result = false;
        try {
            using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) {
                var asyncResult = socket.BeginConnect(yourUri.AbsoluteUri, 80, null, null);
                result = asyncResult.AsyncWaitHandle.WaitOne(100, true);
                socket.Close();
            }
        }
        catch { }
        return result;
        

        【讨论】:

          猜你喜欢
          • 2011-03-06
          • 1970-01-01
          • 1970-01-01
          • 2011-02-11
          • 2020-02-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-02-01
          相关资源
          最近更新 更多