[c#] 콘솔 애플리케이션의 진행률 표시 줄

sftp 서버에 파일을 업로드하는 간단한 C # 콘솔 앱을 작성 중입니다. 그러나 파일의 양이 많습니다. 업로드 할 총 파일 수에서 업로드 된 파일의 비율 또는 이미 업로드 된 파일 수를 표시하고 싶습니다.

먼저 모든 파일과 총 파일 수를 얻습니다.

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

그런 다음 파일을 반복하고 foreach 루프에서 하나씩 업로드합니다.

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 루프에는 문제가있는 진행률 표시 줄이 있습니다. 제대로 표시되지 않습니다.

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
}

출력은 1943 중 [] 0입니다.

내가 여기서 뭘 잘못하고 있니?

편집하다:

XML 파일을로드하고 내보내는 동안 진행률 표시 줄을 표시하려고합니다. 그러나 그것은 루프를 거치고 있습니다. 첫 번째 라운드가 끝나면 두 번째 라운드로 넘어갑니다.

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 루프를 떠나지 않습니다 … 제안 사항이 있습니까?



답변

이 줄이 문제입니다.

drawTextProgressBar(0, totalCount);

당신은 모든 반복에서 진행률이 0이라고 말하고 있습니다. 이것은 증가되어야합니다. 대신 for 루프를 사용할 수 있습니다.

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


답변

콘솔 진행률 표시 줄도 찾고있었습니다. 나는 내가 필요로하는 일을하는 것을 찾지 못해서 나만의 것을 결정하기로 결정했습니다. 소스 코드 (MIT 라이선스) 를 보려면 여기를 클릭하십시오 .

애니메이션 진행률 표시 줄

풍모:

  • 리디렉션 된 출력과 함께 작동

    콘솔 애플리케이션 (예 :)의 출력을 리디렉션하면 Program.exe > myfile.txt대부분의 구현이 예외와 함께 충돌합니다. 그의는 때문에 Console.CursorLeftConsole.SetCursorPosition()리디렉션 된 출력을 지원하지 않습니다.

  • 구현 IProgress<double>

    이렇게하면 [0..1] 범위의 진행 상황을보고하는 비동기 작업과 함께 진행률 표시 줄을 사용할 수 있습니다.

  • 스레드로부터 안전

  • 빠른

    Console클래스는 저속한 성능으로 유명합니다. 너무 많은 호출이 발생하여 애플리케이션 속도가 느려집니다. 이 클래스는 진행률 업데이트를보고하는 빈도에 관계없이 초당 8 번의 호출 만 수행합니다.

다음과 같이 사용하십시오.

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


답변

나는 이것이 오래된 스레드라는 것을 알고 있으며 자체 프로모션에 대해 사과하지만 최근에 nuget Goblinfactory 에서 사용할 수있는 오픈 소스 콘솔 라이브러리를 작성 했습니다. 메인 스레드를 차단하지 않습니다.

다운로드 및 작업을 병렬로 시작하고 다른 작업을 계속할 수 있으므로 위의 답변과 다소 다릅니다.

건배, 도움이 되었기를 바랍니다.

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

이러한 유형의 출력을 제공합니다.

여기에 이미지 설명 입력

Nuget 패키지에는 전체 클리핑 및 래핑 지원과 함께 PrintAt다양한 기타 유용한 클래스와 함께 콘솔의 창 섹션에 쓰기위한 유틸리티도 포함되어 있습니다 .

빌드 및 운영 콘솔 스크립트와 유틸리티를 작성할 때마다 공통 콘솔 루틴을 많이 작성했기 때문에 nuget 패키지를 작성했습니다.

여러 파일을 다운로드하는 경우 Console.Write에는 각 스레드의 화면으로 천천히 이동하고 화면에서 인터리브 된 출력을 더 쉽게 읽을 수 있도록 다양한 방법 (예 : 다른 색상 또는 숫자)을 시도했습니다. 결국 다른 스레드의 출력을 다른 창에 간단히 인쇄 할 수 있도록 창 라이브러리를 작성했으며 유틸리티 스크립트에서 수많은 상용구 코드를 줄였습니다.

예를 들어이 코드는

        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

이것을 생산

여기에 이미지 설명 입력

창에 쓰는 것처럼 쉽게 창 안에 진행률 표시 줄을 만들 수도 있습니다. (믹스 앤 매치).


답변

https://www.nuget.org/packages/ShellProgressBar/ 시도해 볼 수 있습니다.

저는이 진행률 표시 줄 구현을 우연히 발견했습니다. 크로스 플랫폼은 정말 사용하기 쉽고 구성이 가능하며 바로 사용할 수있는 작업을 수행합니다.

내가 많이 좋아해서 그냥 공유.


답변

귀하의 ProgressBar방법 을 복사했습니다 . 귀하의 오류가 언급 된 수락 된 답변으로 루프에 있었기 때문입니다. 그러나이 ProgressBar방법에는 구문 오류도 있습니다. 다음은 작동 버전입니다. 약간 수정되었습니다.

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에는 https://stackoverflow.com/a/31193455/169714 가 더 나은 접근 방식이 있습니다.


답변

원래 포스터의 진행률 표시 줄이 마음에 들었지만 특정 진행률 / 전체 항목 조합에서 진행률이 올바르게 표시되지 않는 것을 발견했습니다. 예를 들어 다음은 올바르게 그려지지 않아 진행률 표시 줄 끝에 추가 회색 블록이 남습니다.

drawTextProgressBar(4114, 4114)

위의 문제를 해결하고 작업 속도를 상당히 높일 수있는 불필요한 루프를 제거하기 위해 일부 드로잉 코드를 다시 수행했습니다.

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
}


답변

System.Reactive와 함께 작동하는이 편리한 클래스를 만들었습니다. 충분히 사랑스럽기를 바랍니다.

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