Piszę prostą aplikację konsoli C #, która przesyła pliki na serwer SFTP. Jednak liczba plików jest duża. Chciałbym wyświetlić procent przesłanych plików lub tylko liczbę przesłanych plików z łącznej liczby plików do przesłania.
Najpierw otrzymuję wszystkie pliki i całkowitą liczbę plików.
string[] filePath = Directory.GetFiles(path, "*");
totalCount = filePath.Length;
Następnie przeglądam plik w pętli i przesyłam je jeden po drugim w pętli 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);
}
W pętli foreach mam pasek postępu, z którym mam problemy. Nie wyświetla się poprawnie.
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
}
Wynik to tylko [] 0 z 1943 roku
Co ja tu robię źle?
EDYTOWAĆ:
Próbuję wyświetlić pasek postępu podczas ładowania i eksportowania plików XML. Jednak przechodzi przez pętlę. Po zakończeniu pierwszej rundy przechodzi do drugiej i tak dalej.
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++;
}
}
Nigdy nie opuszcza pętli for ... Jakieś sugestie?
ExportXml(xmlFilePath[i])
Odpowiedzi:
Ten wiersz jest twoim problemem:
drawTextProgressBar(0, totalCount);
Mówisz, że postęp jest zerowy w każdej iteracji, to powinno być zwiększane. Może zamiast tego użyj pętli 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); }
źródło
Szukałem też paska postępu konsoli. Nie znalazłem takiego, który zrobiłby to, czego potrzebowałem, więc zdecydowałem się na własną. Kliknij tutaj, aby uzyskać kod źródłowy (licencja MIT).
Funkcje:
Działa z przekierowanym wyjściem
Jeśli przekierowujesz dane wyjściowe aplikacji konsolowej (np.
Program.exe > myfile.txt
), Większość implementacji ulegnie awarii z wyjątkiem. Dzieje się tak, ponieważConsole.CursorLeft
iConsole.SetCursorPosition()
nie obsługują przekierowanego wyjścia.Przybory
IProgress<double>
Pozwala to na używanie paska postępu z operacjami asynchronicznymi, które zgłaszają postęp w zakresie [0..1].
Bezpieczne dla wątków
Szybki
Console
Klasa jest znany ze swojej wydajności fatalne. Zbyt wiele wywołań powoduje spowolnienie aplikacji. Ta klasa wykonuje tylko 8 wywołań na sekundę, bez względu na to, jak często zgłaszasz aktualizację postępu.Użyj tego w ten sposób:
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.");
źródło
Wiem, że to stary wątek i przepraszam za autopromocję, jednak niedawno napisałem bibliotekę konsoli open source dostępną w nuget Goblinfactory Konsola z obsługą wielu pasków postępu Threadafe , która może pomóc każdemu nowemu na tej stronie, który potrzebuje takiej, która nie blokuje głównego wątku.
Jest to nieco inne od powyższych odpowiedzi, ponieważ umożliwia równoległe rozpoczęcie pobierania i zadań oraz kontynuowanie innych zadań;
okrzyki, mam nadzieję, że to pomoże
ZA
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.");
daje ten typ wyniku
Pakiet nuget zawiera również narzędzia do pisania w sekcji okna konsoli z pełną obsługą obcinania i zawijania, a także
PrintAt
a także różne inne pomocne klasy.Napisałem pakiet nuget, ponieważ zawsze pisałem wiele typowych procedur konsoli za każdym razem, gdy pisałem skrypty i narzędzia do kompilacji i opsowania konsoli.
Jeśli ściągałem kilka plików, zwykłem powoli przesuwać
Console.Write
się do ekranu w każdym wątku i próbowałem różnych sztuczek, aby ułatwić odczytanie przeplatanego wyjścia na ekranie, np. Różne kolory lub liczby. Ostatecznie napisałem bibliotekę okienkową, aby dane wyjściowe z różnych wątków mogły być po prostu drukowane w różnych oknach, co zmniejszyło tonę standardowego kodu w moich skryptach narzędziowych.Na przykład ten 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
produkuje to
Możesz także tworzyć paski postępu w oknie tak samo łatwo, jak pisanie w oknach. (mieszać i łączyć).
źródło
Możesz spróbować https://www.nuget.org/packages/ShellProgressBar/
Właśnie natknąłem się na tę implementację paska postępu - tak naprawdę jest to platforma wieloplatformowa łatwą w użyciu, dość konfigurowalną i robi to, co powinno od razu po wyjęciu z pudełka.
Udostępnianie, bo bardzo mi się to podobało.
źródło
Skopiowałem twoją
ProgressBar
metodę. Ponieważ twój błąd był w pętli, jak wspomniano w zaakceptowanej odpowiedzi. AleProgressBar
metoda ma również pewne błędy składniowe. Oto wersja robocza. Lekko zmieniony.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 }
Należy pamiętać, że @ Daniel-wolf ma lepsze podejście: https://stackoverflow.com/a/31193455/169714
źródło
Stworzyłem tę poręczną klasę, która działa z System.Reactive. Mam nadzieję, że uznasz to za wystarczająco miłe.
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(); } }
źródło
Bardzo podobał mi się pasek postępu oryginalnego plakatu, ale okazało się, że nie wyświetlał on poprawnie postępu w przypadku niektórych kombinacji postęp / łączna liczba przedmiotów. Na przykład poniższe elementy nie rysują się prawidłowo, pozostawiając dodatkowy szary blok na końcu paska postępu:
drawTextProgressBar(4114, 4114)
Ponownie wykonałem część kodu rysującego, aby usunąć niepotrzebne zapętlenie, które rozwiązało powyższy problem, a także przyspieszyło trochę:
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 }
źródło
Właśnie natknąłem się na ten wątek, szukając czegoś innego i pomyślałem, że zostawię swój kod, który złożyłem razem, który pobiera listę plików za pomocą DownloadProgressChanged. Uważam, że jest to bardzo pomocne, więc widzę nie tylko postęp, ale także rzeczywisty rozmiar w miarę przesyłania pliku. Mam nadzieję, że to komuś pomoże!
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) { }
Oto przykład wyniku:
Mam nadzieję, że to komuś pomoże!
źródło
Wciąż jestem trochę nowy,
C#
ale uważam, że poniższe informacje mogą pomó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++; }
źródło