Я пишу простое консольное приложение С #, которое загружает файлы на сервер sftp. Однако количество файлов велико. Я хотел бы отображать либо процент загруженных файлов, либо просто количество уже загруженных файлов от общего количества файлов, которые нужно загрузить.
Сначала я получаю все файлы и общее количество файлов.
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
}
На выходе всего [] 0 из 1943 г.
Что я здесь делаю не так?
РЕДАКТИРОВАТЬ:
Я пытаюсь отобразить индикатор выполнения при загрузке и экспорте файлов 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 ... Есть предложения?
ExportXml(xmlFilePath[i])
Ответы:
Эта строка - ваша проблема:
drawTextProgressBar(0, totalCount);
Вы говорите, что прогресс равен нулю на каждой итерации, его следует увеличивать. Возможно, вместо этого используйте цикл 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
производит это
Вы также можете создавать индикаторы выполнения внутри окна так же легко, как писать в окнах. (смешивать и сочетать).
источник
Вы можете попробовать 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
источник
Я создал этот удобный класс, который работает с 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(); } }
источник
Мне очень понравился индикатор выполнения оригинального плаката, но я обнаружил, что он некорректно отображает прогресс при определенных комбинациях прогресса / общего количества элементов. Следующее, например, не отрисовывается правильно, оставляя лишний серый блок в конце индикатора выполнения:
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 }
источник
Я просто наткнулся на эту ветку в поисках чего-то еще, и подумал, что оставлю свой код, который я собрал, который загружает список файлов с помощью 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++; }
источник