web-dev-qa-db-fra.com

Barre de progression dans l'application console

J'écris une simple application de console c # qui télécharge des fichiers sur un serveur sftp. Cependant, le nombre de fichiers est important. Je souhaite afficher soit le pourcentage de fichiers téléchargés, soit le nombre de fichiers déjà téléchargés par rapport au nombre total de fichiers à télécharger.

Tout d'abord, je reçois tous les fichiers et le nombre total de fichiers.

string[] filePath = Directory.GetFiles(path, "*");
totalCount = filePath.Length;

Ensuite, je parcours le fichier et les télécharge un par un dans chaque boucle.

foreach(string file in filePath)
{
    string FileName = Path.GetFileName(file);
    //copy the files
    oSftp.Put(LocalDirectory + "/" + FileName, _ftpDirectory + "/" + FileName);
    //Console.WriteLine("Uploading file..." + FileName);
    drawTextProgressBar(0, totalCount);
}

Dans la boucle foreach, j'ai une barre de progression qui me pose problème. Cela ne s'affiche pas correctement.

private static void drawTextProgressBar(int progress, int total)
{
    //draw empty progress bar
    Console.CursorLeft = 0;
    Console.Write("["); //start
    Console.CursorLeft = 32;
    Console.Write("]"); //end
    Console.CursorLeft = 1;
    float onechunk = 30.0f / total;

    //draw filled part
    int position = 1;
    for (int i = 0; i < onechunk * progress; i++)
    {
        Console.BackgroundColor = ConsoleColor.Gray;
        Console.CursorLeft = position++;
        Console.Write(" ");
    }

    //draw unfilled part
    for (int i = position; i <= 31 ; i++)
    {
        Console.BackgroundColor = ConsoleColor.Green;
        Console.CursorLeft = position++;
        Console.Write(" ");
    }

    //draw totals
    Console.CursorLeft = 35;
    Console.BackgroundColor = ConsoleColor.Black;
    Console.Write(progress.ToString() + " of " + total.ToString() + "    "); //blanks at the end remove any excess
}

La sortie est juste [] 0 sur 1943

Qu'est-ce que je fais mal ici? 

MODIFIER:

J'essaie d'afficher la barre de progression pendant le chargement et l'exportation de fichiers XML. Cependant, cela passe par une boucle. Une fois le premier tour terminé, il passe au second et ainsi de suite.

string[] xmlFilePath = Directory.GetFiles(xmlFullpath, "*.xml");
Console.WriteLine("Loading XML files...");
foreach (string file in xmlFilePath)
{
     for (int i = 0; i < xmlFilePath.Length; i++)
     {
          //ExportXml(file, styleSheet);
          drawTextProgressBar(i, xmlCount);
          count++;
     }
 }

Il ne laisse jamais la boucle perdue ... Des suggestions?

61
smr5

Cette ligne est votre problème:

drawTextProgressBar(0, totalCount);

Vous dites que le progrès est nul à chaque itération, cela devrait être incrémenté. Peut-être utilisez-vous une boucle for à la place.

for (int i = 0; i < filePath.length; i++)
{
    string FileName = Path.GetFileName(filePath[i]);
    //copy the files
    oSftp.Put(LocalDirectory + "/" + FileName, _ftpDirectory + "/" + FileName);
    //Console.WriteLine("Uploading file..." + FileName);
    drawTextProgressBar(i, totalCount);
}
9
eddie_cat

Je cherchais aussi une barre de progression de la console. Je n’en ai trouvé aucun qui répondait à mes besoins, j’ai donc décidé de lancer le mien. Cliquez ici pour le code source (Licence MIT).

Animated progress bar

Caractéristiques:

  • Fonctionne avec une sortie redirigée

    Si vous redirigez la sortie d'une application console (par exemple, Program.exe > myfile.txt), la plupart des implémentations planteront avec une exception. En effet, Console.CursorLeft et Console.SetCursorPosition() ne prennent pas en charge les sorties redirigées.

  • Implements IProgress<double>

    Cela vous permet d'utiliser la barre de progression avec des opérations asynchrones qui signalent une progression de l'ordre de [0..1].

  • Fil-safe

  • Vite

    La classe Console est réputée pour ses performances abyssales. Trop d'appels et votre application ralentit. Cette classe effectue seulement 8 appels par seconde, quelle que soit la fréquence à laquelle vous signalez une mise à jour de progression.

Utilisez-le comme ceci:

Console.Write("Performing some task... ");
using (var progress = new ProgressBar()) {
    for (int i = 0; i <= 100; i++) {
        progress.Report((double) i / 100);
        Thread.Sleep(20);
    }
}
Console.WriteLine("Done.");
135
Daniel Wolf

Je sais que c’est un vieux fil, et j’excuse pour la promotion, mais j’ai récemment écrit une bibliothèque de console open source disponible sur nuget Goblinfactory.Konsole avec le support threadsafe de barres de progression multiples, qui pourrait aider les débutants page ayant besoin d'une page qui ne bloque pas le fil principal. 

Les réponses ci-dessus diffèrent quelque peu, car elles vous permettent de lancer les téléchargements et les tâches en parallèle et de poursuivre d'autres tâches.

à la vôtre, j'espère que c'est utile

UNE

var t1 = Task.Run(()=> {
   var p = new ProgressBar("downloading music",10);
   ... do stuff
});

var t2 = Task.Run(()=> {
   var p = new ProgressBar("downloading video",10);
   ... do stuff
});

var t3 = Task.Run(()=> {
   var p = new ProgressBar("starting server",10);
   ... do stuff .. calling p.Refresh(n);
});

Task.WaitAll(new [] { t1,t2,t3 }, 20000);
Console.WriteLine("all done.");

vous donne ce type de sortie 

 enter image description here

Le paquet Nuget inclut également des utilitaires permettant d’écrire dans une section fenêtrée de la console avec prise en charge complète des découpages et des encapsulages, ainsi que PrintAt et diverses autres classes utiles. 

J'ai écrit le paquet Nuget parce que je finissais constamment par écrire de nombreuses routines de console communes lorsque j'écrivais des scripts et des utilitaires de console de compilation et d'exploitation.

Si je téléchargeais plusieurs fichiers, j’utilisais lentement Console.Write à l’écran de chaque fil et je tentais diverses astuces pour rendre la lecture de la sortie entrelacée plus facile à l’écran, par exemple. différentes couleurs ou numéros. J'ai finalement écrit la bibliothèque de fenêtrage afin que la sortie de différents threads puisse simplement être imprimée sur différentes fenêtres et que cela réduise une tonne de code standard dans mes scripts utilitaires. 

Par exemple, ce code,

        var con = new Window(200,50);
        con.WriteLine("starting client server demo");
        var client = new Window(1, 4, 20, 20, ConsoleColor.Gray, ConsoleColor.DarkBlue, con);
        var server = new Window(25, 4, 20, 20, con);
        client.WriteLine("CLIENT");
        client.WriteLine("------");
        server.WriteLine("SERVER");
        server.WriteLine("------");
        client.WriteLine("<-- PUT some long text to show wrapping");
        server.WriteLine(ConsoleColor.DarkYellow, "--> PUT some long text to show wrapping");
        server.WriteLine(ConsoleColor.Red, "<-- 404|Not Found|some long text to show wrapping|");
        client.WriteLine(ConsoleColor.Red, "--> 404|Not Found|some long text to show wrapping|");

        con.WriteLine("starting names demo");
        // let's open a window with a box around it by using Window.Open
        var names = Window.Open(50, 4, 40, 10, "names");
        TestData.MakeNames(40).OrderByDescending(n => n).ToList()
             .ForEach(n => names.WriteLine(n));

        con.WriteLine("starting numbers demo");
        var numbers = Window.Open(50, 15, 40, 10, "numbers", 
              LineThickNess.Double,ConsoleColor.White,ConsoleColor.Blue);
        Enumerable.Range(1,200).ToList()
             .ForEach(i => numbers.WriteLine(i.ToString())); // shows scrolling

produit cette

 enter image description here

Vous pouvez également créer des barres de progression dans une fenêtre aussi facilement que d'écrire dans les fenêtres. (mélanger et assortir).

11
snowcode

J'ai copié votre méthode ProgressBar. Parce que votre erreur était dans la boucle, comme le dit la réponse acceptée. Mais la méthode ProgressBar a aussi des erreurs de syntaxe. Voici la version de travail. Légèrement modifié.

private static void ProgressBar(int progress, int tot)
{
    //draw empty progress bar
    Console.CursorLeft = 0;
    Console.Write("["); //start
    Console.CursorLeft = 32;
    Console.Write("]"); //end
    Console.CursorLeft = 1;
    float onechunk = 30.0f / tot;

    //draw filled part
    int position = 1;
    for (int i = 0; i < onechunk * progress; i++)
    {
        Console.BackgroundColor = ConsoleColor.Green;
        Console.CursorLeft = position++;
        Console.Write(" ");
    }

    //draw unfilled part
    for (int i = position; i <= 31; i++)
    {
        Console.BackgroundColor = ConsoleColor.Gray;
        Console.CursorLeft = position++;
        Console.Write(" ");
    }

    //draw totals
    Console.CursorLeft = 35;
    Console.BackgroundColor = ConsoleColor.Black;
    Console.Write(progress.ToString() + " of " + tot.ToString() + "    "); //blanks at the end remove any excess
}

Notez que @ Daniel-wolf adopte une meilleure approche: https://stackoverflow.com/a/31193455/169714

5
JP Hellemons

J'ai bien aimé la barre de progression de l'affiche originale, mais j'ai constaté qu'elle ne affichait pas la progression correctement avec certaines combinaisons de progression/nombre total d'éléments. Ce qui suit, par exemple, ne dessine pas correctement, laissant un bloc gris supplémentaire à la fin de la barre de progression:

drawTextProgressBar(4114, 4114)

J'ai refait une partie du code de dessin pour supprimer les boucles inutiles qui corrigeaient le problème ci-dessus et accéléraient un peu les choses:

public static void drawTextProgressBar(string stepDescription, int progress, int total)
{
    int totalChunks = 30;

    //draw empty progress bar
    Console.CursorLeft = 0;
    Console.Write("["); //start
    Console.CursorLeft = totalChunks + 1;
    Console.Write("]"); //end
    Console.CursorLeft = 1;

    double pctComplete = Convert.ToDouble(progress) / total;
    int numChunksComplete = Convert.ToInt16(totalChunks * pctComplete);

    //draw completed chunks
    Console.BackgroundColor = ConsoleColor.Green;
    Console.Write("".PadRight(numChunksComplete));

    //draw incomplete chunks
    Console.BackgroundColor = ConsoleColor.Gray;
    Console.Write("".PadRight(totalChunks - numChunksComplete));

    //draw totals
    Console.CursorLeft = totalChunks + 5;
    Console.BackgroundColor = ConsoleColor.Black;

    string output = progress.ToString() + " of " + total.ToString();
    Console.Write(output.PadRight(15) + stepDescription); //pad the output so when changing from 3 to 4 digits we avoid text shifting
}
3
Nico M

Vous voudrez peut-être essayer https://www.nuget.org/packages/ShellProgressBar/

Je suis tombé par hasard sur cette mise en œuvre de la barre de progression - sa plate-forme croisée, vraiment facile à utiliser, tout à fait configurable et fait ce qu’elle devrait d’emblée. 

Partager juste parce que ça me plaisait beaucoup.

2
Schweder

J'ai créé cette classe pratique qui fonctionne avec System.Reactive. J'espère que vous le trouverez assez joli.

public class ConsoleDisplayUpdater : IDisposable
{
    private readonly IDisposable progressUpdater;

    public ConsoleDisplayUpdater(IObservable<double> progress)
    {
        progressUpdater = progress.Subscribe(DisplayProgress);
    }

    public int Width { get; set; } = 50;

    private void DisplayProgress(double progress)
    {
        if (double.IsNaN(progress))
        {
            return;
        }

        var progressBarLenght = progress * Width;
        System.Console.CursorLeft = 0;
        System.Console.Write("[");
        var bar = new string(Enumerable.Range(1, (int) progressBarLenght).Select(_ => '=').ToArray());

        System.Console.Write(bar);

        var label = $@"{progress:P0}";
        System.Console.CursorLeft = (Width -label.Length) / 2;
        System.Console.Write(label);
        System.Console.CursorLeft = Width;
        System.Console.Write("]");
    }

    public void Dispose()
    {
        progressUpdater?.Dispose();
    }
}

https://github.com/WOA-project/WOA-Deployer/blob/master/Source/Deployer.Lumia.Console/ConsoleDisplayUpdater.cs

0
SuperJMN

Je suis juste tombé par hasard sur ce fil à la recherche de quelque chose d'autre, et j'ai pensé déposer mon code que j'ai mis ensemble pour télécharger une liste de fichiers en utilisant DownloadProgressChanged. Je trouve cela très utile, donc je ne vois pas seulement les progrès, mais la taille réelle du fichier. J'espère que ça aide quelqu'un!

public static bool DownloadFile(List<string> files, string Host, string username, string password, string savePath)
    {
        try
        {
            //setup FTP client

            foreach (string f in files)
            {
                FILENAME = f.Split('\\').Last();
                wc.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
                wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(ProgressChanged);
                wc.DownloadFileAsync(new Uri(Host + f), savePath + f);
                while (wc.IsBusy)
                    System.Threading.Thread.Sleep(1000);
                Console.Write("  COMPLETED!");
                Console.WriteLine();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
            return false;
        }
        return true;
    }

    private static void ProgressChanged(object obj, System.Net.DownloadProgressChangedEventArgs e)
    {
        Console.Write("\r --> Downloading " + FILENAME +": " + string.Format("{0:n0}", e.BytesReceived / 1000) + " kb");
    }

    private static void Completed(object obj, AsyncCompletedEventArgs e)
    {
    }

Voici un exemple de sortie: enter image description here

J'espère que ça aide quelqu'un!

0
Ted Krapf