Konsol uygulamasında ilerleme çubuğu


84

Dosyaları sftp sunucusuna yükleyen basit bir c # konsol uygulaması yazıyorum. Ancak, dosya miktarı büyüktür. Ya yüklenen dosyaların yüzdesini ya da yüklenecek toplam dosya sayısından halihazırda yüklenen dosyaların sayısını görüntülemek istiyorum.

İlk olarak, tüm dosyaları ve toplam dosya sayısını alıyorum.

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

Sonra dosyada döngü yapıyorum ve bunları foreach döngüsünde birer birer yüklüyorum.

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

Foreach döngüsünde sorunlarım olan bir ilerleme çubuğum var. Düzgün görüntülenmiyor.

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
}

Çıktı 1943'te sadece [] 0

Burada neyi yanlış yapıyorum?

DÜZENLE:

XML dosyalarını yüklerken ve dışa aktarırken ilerleme çubuğunu görüntülemeye çalışıyorum. Ancak, bir döngüden geçiyor. İlk turu bitirdikten sonra ikinci tura geçer ve böyle devam eder.

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

For döngüsünü asla terk etmez ... Herhangi bir öneriniz var mı?


XmlCount ve count nedir?
eddie_cat

Sadece artışı sayın. xmlCount, belirtilen klasördeki toplam XML dosyası sayısıdır DirectoryInfo xmlDir = new DirectoryInfo (xmlFullpath); xmlCount = xmlDir.GetFiles (). Uzunluk;
smr5

1
Ayrıca, for döngüsü neden foreach döngüsünün içinde? Aynı şey üzerinde yineleniyor gibi görünüyor. Foreach döngüsünü sürdürmek muhtemelen gerekli değildir.
eddie_cat

1
Dış foreach döngüsünü çıkardınız mı? ExportXml(xmlFilePath[i])
Yorumlanan

1
İşte buydu. Sadece for döngüsüne sahibim ve işe yarıyor.
smr5

Yanıtlar:


11

Bu satır senin sorunun:

drawTextProgressBar(0, totalCount);

Her yinelemede ilerlemenin sıfır olduğunu söylüyorsunuz, bu artırılmalıdır. Belki bunun yerine bir for döngüsü kullanın.

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

İlk seferinde çalıştı ve ben aynı şeyi diğer yerde aynı yerde yapıyorum ve bu bir döngüye neden oluyor. Asla durmaz. Yazımı güncelledim. Şuna bir bakar mısın? Teşekkürler.
smr5

Neyi güncelledin? Bana aynı görünüyor, neyi özlüyorum?
eddie_cat

200

Ayrıca bir konsol ilerleme çubuğu arıyordum. İhtiyacım olanı yapan bir tane bulamadım, bu yüzden kendim yapmaya karar verdim. Kaynak kodu (MIT Lisansı) için buraya tıklayın .

Animasyonlu ilerleme çubuğu

Özellikleri:

  • Yönlendirilmiş çıktıyla çalışır

    Bir konsol uygulamasının (örneğin Program.exe > myfile.txt) çıktısını yeniden yönlendirirseniz , çoğu uygulama bir istisna ile çöker. Bunun nedeni Console.CursorLeft, Console.SetCursorPosition()yeniden yönlendirilmiş çıktıyı desteklememesidir.

  • Uygulamalar IProgress<double>

    Bu, [0..1] aralığında bir ilerleme bildiren eşzamansız işlemlerle ilerleme çubuğunu kullanmanıza olanak tanır.

  • İş parçacığı güvenli

  • Hızlı

    ConsoleSınıf onun dipsiz performansı için tanınıyor. Çok fazla çağrı var ve uygulamanız yavaşlıyor. Bu sınıf, bir ilerleme güncellemesini ne sıklıkla bildirirseniz bildirin, saniyede yalnızca 8 çağrı yapar.

Bunu şu şekilde kullanın:

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.");

4
Bu oldukça temiz görünüyor! MIT gibi bir OSS lisansı eklemeyi düşünür müsünüz? selectalicense.com
Daniel Plaisted

2
İyi bir fikir. Bunu yaptım.
Daniel Wolf

@DanielWolf, CursorPosition'ı değiştirerek Console.Write'ı nasıl edindiniz?
JJS

1
@knocte: Üretim kodunda kesinlikle yapardım. Buradaki amaç, örneği olabildiğince kısa tutmak ve ilgisini ilgili kısımlardan uzaklaştırmamaktı.
Daniel Wolf

8
Gif çekici.
Lei Yang

18

Bunun eski bir iş parçacığı olduğunu biliyorum ve kendi tanıtımım için özür dilerim, ancak kısa süre önce nuget Goblinfactory.Konsole'da threadafe çoklu ilerleme çubuğu desteğine sahip bir açık kaynak konsol kitaplığı yazdım , bu sayfada yeni olanlara ihtiyaç duyan herkese yardımcı olabilir ana ileti dizisini engellemez.

İndirmeleri ve görevleri paralel olarak başlatmanıza ve diğer görevlere devam etmenize izin verdiği için yukarıdaki cevaplardan biraz farklıdır;

Şerefe, umarım bu yardımcı olur

Bir

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.");

size bu tür çıktılar verir

görüntü açıklamasını buraya girin

Nuget paketi ayrıca, konsolun pencereli bir bölümüne tam kırpma ve sarma desteğiyle birlikte yazmak için yardımcı programlar ve ayrıca PrintAtdiğer çeşitli yararlı sınıflar içerir.

Nuget paketini yazdım çünkü her ne zaman build ve ops konsol betikleri ve yardımcı programları yazdığımda sürekli olarak birçok ortak konsol rutini yazdım.

Birkaç dosya Console.Writeindiriyorsam, her bir iş parçacığındaki ekrana yavaşça gittim ve ekranda serpiştirilmiş çıktının okunmasını kolaylaştırmak için çeşitli hileler denerdim, örneğin farklı renkler veya sayılar. Sonunda pencereleme kitaplığını yazdım, böylece farklı iş parçacıklarından gelen çıktılar farklı pencerelere yazdırılabilir ve yardımcı program betiklerimdeki bir ton standart kod kesildi.

Örneğin bu kod,

        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

bunu üretir

görüntü açıklamasını buraya girin

Ayrıca pencerelere yazmak kadar kolay bir şekilde bir pencere içinde ilerleme çubukları da oluşturabilirsiniz. (karıştır ve Eşleştir).


Bu sadece en iyisi
Pratik

9

Https://www.nuget.org/packages/ShellProgressBar/ denemek isteyebilirsiniz.

Bu ilerleme çubuğu uygulamasına henüz rastladım - çapraz platformu, kullanımı gerçekten kolay, oldukça yapılandırılabilir ve kutudan çıkar çıkmaz yapması gerekeni yapıyor.

Sadece paylaşıyorum çünkü çok beğendim.


6

ProgressBarYöntemini kopyaladım . Çünkü hatanız belirtilen cevap olarak kabul edilen döngüdeydi. Ancak ProgressBaryöntemin bazı sözdizimi hataları da var. İşte çalışan versiyon. Biraz değiştirildi.

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
}

@ Daniel-wolf'un daha iyi bir yaklaşımı olduğunu lütfen unutmayın: https://stackoverflow.com/a/31193455/169714


6

System.Reactive ile çalışan bu kullanışlı sınıfı oluşturdum. Umarım yeterince güzel bulursun.

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

5

Orijinal posterin ilerleme çubuğunu oldukça beğendim, ancak belirli ilerleme / toplam öğe kombinasyonlarında ilerlemeyi doğru şekilde göstermediğini gördüm. Örneğin aşağıdakiler doğru çizilmez ve ilerleme çubuğunun sonunda fazladan gri bir blok bırakır:

drawTextProgressBar(4114, 4114)

Yukarıdaki sorunu çözen ve aynı zamanda işleri biraz hızlandıran gereksiz döngüleri kaldırmak için çizim kodunun bir kısmını yeniden yaptım:

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
}

bu, önceki konsol çıktılarını ondan önceki herhangi bir metin gibi silmesi ve bundan sonra yeni bir satıra gitmemesi dışında genel olarak çalışır ....
David Shnayder

0

Bu iş parçacığına başka bir şey ararken rastladım ve DownloadProgressChanged kullanarak dosyaların bir listesini indiren kodumu bir araya getirdiğimi düşündüm. Bunu çok yararlı buluyorum, bu yüzden sadece ilerlemeyi değil, aynı zamanda dosyanın geldiği gerçek boyutu da görüyorum. Umarım birine yardımcı olur!

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

İşte çıktıya bir örnek: görüntü açıklamasını buraya girin

Umarım birine yardımcı olur!


2
@regisbsb Bunlar ilerleme çubukları değil, dosya adlarının bir kısmını sansürlemiş gibi görünüyor :) Biliyorum, ilk başta kendimi de kandırdım.
silkfire

-1

Hala biraz yeniyim C#ama aşağıdakilerin yardımcı olabileceğine inanıyorum.

string[] xmlFilePath = Directory.GetFiles(xmlFullpath, "*.xml");
Console.WriteLine("Loading XML files...");
int count = 0;
foreach (string file in xmlFilePath)
{
    //ExportXml(file, styleSheet);
    drawTextProgressBar(count, xmlCount);
    count++;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.