简体   繁体   中英

How can I write out correctly the download status in C# console app?

I have the following code, and it is working correctly except writing out the status of the download.

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

        }
    }
}

With the code many new lines will be inserted and the status of the download will not be updated and printed out.

In my case it works if you will handle DownloadFileCompleted event too.

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

And you should also use client.Dispose() or write your code in using statement:

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

This will automaticly dispose resources.

Edit:

As rene correctly noticed, there is no need in that case to use Dispose but generally it's good to remember that using statement is commonly used with IDisposible or IO operations.

You can call Console.Clear() before every update. This will remove all text from your Console. This would change your code to this:

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

        }
    }
}

For what Thread.Sleep ? Remove it.

If you want to preserve the content of the console then save cursor coordinates and set it each time.

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

DownloadProgressChanged event can be called by multiple threads concurrently, so you need to take care of it, for example using lock as shown bellow.

Also don't use Thread.Sleep() in event handler! It is never good idea. In this particular case, while thread is sleeping, download cannot continue, resulting in significantly slower download. If you want to limit frequency of updates to screen (to lower CPU load and avoid screen flickering), simply skip events that accurs too soon after previous event.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM