【问题标题】:How can I write out correctly the download status in C# console app?如何在 C# 控制台应用程序中正确写出下载状态?
【发布时间】:2017-06-03 15:53:57
【问题描述】:

我有以下代码,除了写出下载状态外,它工作正常。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {

        static void clear()
        {

            Thread.Sleep(1500);
            Console.SetCursorPosition(0, 0);

        }


        static void Main(string[] args)
        {
            var client = new WebClient();          

            client.DownloadProgressChanged += (o, e) =>
            {

                Console.Write(e.ProgressPercentage + "% ");
                clear();


            };            

            client.DownloadFileAsync(new Uri("http://XXX"), "file");

            Console.ReadKey();   

        }
    }
}

该代码将插入许多新行,并且不会更新和打印下载状态。

【问题讨论】:

    标签: c# download status


    【解决方案1】:

    在我的情况下,如果您也处理 DownloadFileCompleted 事件,它就可以工作。

    client.DownloadFileCompleted += (e, s) =>
    {
         Console.WriteLine("Completed!");
    };
    

    您还应该使用 client.Dispose() 或在 using 语句中编写您的代码:

    using (WebClient client = new WebClient())
    {
         // Code which uses WebClient
    }
    

    这将自动释放资源。

    编辑:

    正如 rene 正确注意到的那样,在这种情况下没有必要使用 Dispose 但通常最好记住 using 语句通常与 IDisposible 或 IO 操作一起使用。

    【讨论】:

    【解决方案2】:

    DownloadProgressChanged事件可以被多个线程同时调用,所以你需要注意它,例如使用lock,如下所示。

    也不要在事件处理程序中使用Thread.Sleep()!这从来都不是好主意。在这种特殊情况下,当线程处于休眠状态时,下载无法继续,导致下载速度明显变慢。如果您想限制屏幕更新频率(以降低 CPU 负载并避免屏幕闪烁),只需跳过在前一个事件之后过早发生的事件。

    static void Main(string[] args)
    {
        var client = new WebClient();
    
        Object LockObject = new Object();
        DateTime LastProgressUpdateTime = DateTime.MinValue;
        long LastProgressUpdatePosition = -1;
        TimeSpan DesiredProgressUpdatePeriod = TimeSpan.FromMilliseconds(1500);
    
        client.DownloadProgressChanged += (o, e) =>
        {
            //Prevent multipe concurrent thread to update progress at once
            lock (LockObject)
            {
                // This prevents updating progress to value that is lower than
                // what we already printed. This could happen when threads
                // enters lock out of order.
                if (LastProgressUpdatePosition > e.BytesReceived)
                    return;
    
                // This is not neccessary, but prevents you to miss 100% progress event ()
                var isCompleted = e.TotalBytesToReceive != 0 && e.BytesReceived == e.TotalBytesToReceive;
    
                // Check if desired time elapsed since last update
                bool UpdatePeriodElapsed = DateTime.Now >= LastProgressUpdateTime + DesiredProgressUpdatePeriod;
    
                if(isCompleted || UpdatePeriodElapsed)
                {
                    Console.SetCursorPosition(0, 0);
                    Console.Write(e.ProgressPercentage + "%");
                    LastProgressUpdatePosition = e.BytesReceived;
                    LastProgressUpdateTime = DateTime.Now;
                }
            }
        };
    
        client.DownloadFileAsync(new Uri("..."), "...");
        Console.ReadKey();
    }
    

    【讨论】:

      【解决方案3】:

      您可以在每次更新前调用 Console.Clear()。这将从您的控制台中删除所有文本。这会将您的代码更改为:

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Net;
      using System.Text;
      using System.Threading;
      
      namespace ConsoleApplication1
      {
          class Program
          {
      
              static void clear()
              {
      
                  Thread.Sleep(1500);
                  Console.SetCursorPosition(0, 0);
      
              }
      
      
              static void Main(string[] args)
              {
                  var client = new WebClient();          
      
                  client.DownloadProgressChanged += (o, e) =>
                  {
                      Console.Clear();
                      Console.Write(e.ProgressPercentage + "% ");
                      clear();
      
      
                  };            
      
                  client.DownloadFileAsync(new Uri("http://XXX"), "file");
      
                  Console.ReadKey();   
      
              }
          }
      }
      

      【讨论】:

      • 我想保留控制台的内容。不想删,就一行。
      • 如果你想保留内容而不是你需要一个像 Tom Chantler 描述的帮助类。 post
      【解决方案4】:

      为了什么Thread.Sleep?删除它。

      如果要保留控制台的内容,则保存光标坐标并每次设置。

      using (var client = new WebClient())
      {
          int left = Console.CursorLeft;
          int top = Console.CursorTop;
      
          client.DownloadProgressChanged += (o, e) =>
          {
              Console.SetCursorPosition(left, top);
              Console.Write(e.ProgressPercentage + "% ");
          };
      
          client.DownloadFileAsync(...);
          Console.ReadKey();
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-06-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-14
        • 1970-01-01
        • 2014-02-17
        相关资源
        最近更新 更多