我正在编写一个简单的c#控制台应用程序,它将文件上传到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
}
输出只是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循环......有什么建议吗?
答案 0 :(得分:146)
我还在寻找一个控制台进度条。我没有找到一个能做我需要的东西,所以我决定自己动手。 Click here for the source code(麻省理工学院执照)。
特点:
使用重定向输出
如果重定向控制台应用程序的输出(例如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.");
答案 1 :(得分:11)
我知道这是一个老线程,并为自我推销道歉,但我最近在nuget moment-duration-format上编写了一个开源控制台库,其中包含线程安全的多个进度条支持,这可能对任何人都有帮助需要一个不阻止主线程的页面的新手。
它与上述答案略有不同,因为它允许您并行启动下载和任务并继续执行其他任务;
欢呼,希望这是有帮助的A
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包,因为每当我编写build和ops控制台脚本和实用程序时,我总是会编写许多常用的控制台例程。
如果我正在下载多个文件,我曾经慢慢地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
产生这个
您也可以在窗口内创建进度条,就像写入窗口一样容易。 (混合搭配)。
答案 2 :(得分:9)
这一行是你的问题:
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);
}
答案 3 :(得分:5)
我已复制粘贴您的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
答案 4 :(得分:3)
我非常喜欢原版海报的进度条,但发现它没有正确显示某些进度/总项目组合的进度。例如,以下内容未正确绘制,在进度条的末尾留下了一个额外的灰色块:
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
}
答案 5 :(得分:2)
您可能想尝试https://www.nuget.org/packages/ShellProgressBar/
我只是偶然发现了这个进度条实现 - 它的跨平台,真的易于使用,可配置完成,并且开箱即用。
分享,因为我很喜欢它。
答案 6 :(得分:1)
我创建了这个与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();
}
}
答案 7 :(得分:0)
我偶然发现了这个线程正在寻找其他东西,我想我会放下我使用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)
{
}
这是输出的一个例子:
希望它有所帮助!
答案 8 :(得分:0)
基于以上所有帖子,我做了一个改进版。
没有跳跃光标。现在看不见了。
提高了性能(成本是原始版本的 1/5~1/10 倍)。
基于接口。很容易转移到别的地方。
public class ConsoleProgressBar : IProgressBar
{
private const ConsoleColor ForeColor = ConsoleColor.Green;
private const ConsoleColor BkColor = ConsoleColor.Gray;
private const int DefaultWidthOfBar = 32;
private const int TextMarginLeft = 3;
private readonly int _total;
private readonly int _widthOfBar;
public ConsoleProgressBar(int total, int widthOfBar = DefaultWidthOfBar)
{
_total = total;
_widthOfBar = widthOfBar;
}
private bool _intited;
public void Init()
{
_lastPosition = 0;
//Draw empty progress bar
Console.CursorVisible = false;
Console.CursorLeft = 0;
Console.Write("["); //start
Console.CursorLeft = _widthOfBar;
Console.Write("]"); //end
Console.CursorLeft = 1;
//Draw background bar
for (var position = 1; position < _widthOfBar; position++) //Skip the first position which is "[".
{
Console.BackgroundColor = BkColor;
Console.CursorLeft = position;
Console.Write(" ");
}
}
public void ShowProgress(int currentCount)
{
if (!_intited)
{
Init();
_intited = true;
}
DrawTextProgressBar(currentCount);
}
private int _lastPosition;
public void DrawTextProgressBar(int currentCount)
{
//Draw current chunk.
var position = currentCount * _widthOfBar / _total;
if (position != _lastPosition)
{
_lastPosition = position;
Console.BackgroundColor = ForeColor;
Console.CursorLeft = position >= _widthOfBar ? _widthOfBar - 1 : position;
Console.Write(" ");
}
//Draw totals
Console.CursorLeft = _widthOfBar + TextMarginLeft;
Console.BackgroundColor = ConsoleColor.Black;
Console.Write(currentCount + " of " + _total + " "); //blanks at the end remove any excess
}
}
public interface IProgressBar
{
public void ShowProgress(int currentCount);
}
还有一些测试代码:
var total = 100;
IProgressBar progressBar = new ConsoleProgressBar(total);
for (var i = 0; i <= total; i++)
{
progressBar.ShowProgress(i);
Thread.Sleep(50);
}
Thread.Sleep(500);
Console.Clear();
total = 9999;
progressBar = new ConsoleProgressBar(total);
for (var i = 0; i <= total; i++)
{
progressBar.ShowProgress(i);
}
答案 9 :(得分:-1)
我对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++;
}