콘솔 애플리케이션의 진행률 표시 줄
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.CursorLeft
및Console.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 에서 사용할 수있는 오픈 소스 콘솔 라이브러리를 작성했습니다. 스레드 세이프 다중 진행률 표시 줄 지원이 포함 된 Konsole 은이 페이지를 처음 사용하는 모든 사용자에게 도움이 될 수 있습니다. 메인 스레드를 차단하지 않습니다.
다운로드 및 작업을 병렬로 시작하고 다른 작업을 계속할 수 있으므로 위의 답변과 다소 다릅니다.
건배, 도움이 되길 바랍니다
ㅏ
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
이것을 생산
창에 쓰는 것처럼 쉽게 창 안에 진행률 표시 줄을 만들 수도 있습니다. (믹스 앤 매치).
귀하의 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
}
https://www.nuget.org/packages/ShellProgressBar/ 시도해 볼 수 있습니다.
저는이 진행률 표시 줄 구현을 우연히 발견했습니다. 크로스 플랫폼은 정말 사용하기 쉽고 구성이 가능하며 상자에서 꺼내 자마자 수행해야하는 작업을 수행합니다.
내가 많이 좋아해서 그냥 공유.
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();
}
}
방금이 스레드가 다른 것을 찾고있는 것을 우연히 발견했고, DownloadProgressChanged를 사용하여 파일 목록을 다운로드하는 코드를 모아 놓을 것이라고 생각했습니다. 나는 이것이 매우 유용하다는 것을 알기 때문에 진행 상황뿐만 아니라 파일이 통과하는 실제 크기를 볼 수 있습니다. 누군가에게 도움이되기를 바랍니다!
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)
{
}
다음은 출력의 예입니다.
누군가에게 도움이되기를 바랍니다!
나는 아직 조금 새롭지 C#
만 아래가 도움이 될 것이라고 믿습니다.
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++;
}
참고 URL : https://stackoverflow.com/questions/24918768/progress-bar-in-console-application
'Development Tip' 카테고리의 다른 글
Scala에서 한 번에 여러 예외 잡기 (0) | 2020.11.09 |
---|---|
OS X 또는 iOS (Gestalt를 사용하지 않고)에서 런타임시 OS 버전을 어떻게 확인합니까? (0) | 2020.11.09 |
Laravel Advanced 함수에 변수를 전달하는 방법은 어디입니까? (0) | 2020.11.09 |
HTML에서 공백없이 긴 줄을 감싸는 방법은 무엇입니까? (0) | 2020.11.09 |
PHP 경고 : 알 수 없음 : 스트림을 열지 못했습니다. (0) | 2020.11.09 |