如何在多线程c#中使用基于文本的控制台进度条
本文关键字:文本 控制台 于文本 多线程 | 更新日期: 2023-09-27 18:01:21
嗨,我有一个程序,可以并行(在线程中)下载和提取文件。它是一个控制台应用程序,我想为每个线程中的每个操作显示进度条。例如:
文件1 [==========35%]35mb of 100mb下载
文件2 [====20%]20mb of 100mb下载
File1下载,
文件1 [============= 50 % ] 提取50%。等等。
注意:我能够将控制台输出显示为下面的代码,但希望在我的控制台APP中使用此进度条。
在这种情况下如何使用https://gist.github.com/DanielSWolf/0ab6a96899cc5377bf54中提出的解决方案?
public static void DownloadAndGetFiles()
{
try
{
Parallel.ForEach(FileIds, currentId =>
{
int currentId = FileIds.Id
clientFileDownload(currentId);
});
}
catch (Exception e)
{
}
}
private static void clientFileDownload(int currentId)
{
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
string downloadedFile = @"d:'tmp'";
client.DownloadFileAsync(new Uri(currentId.URL), downloadedFile); //some URL
while (client.IsBusy) { }
string temp = ExtractAndRename(currentId);
}
private static void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
//Prints: "Downloaded 3mb of 61.46mb (4%)"
Console.WriteLine("Downloaded "
+ ((e.BytesReceived / 1024f) / 1024f).ToString("#0.##") + "mb"
+ " of "
+ ((e.TotalBytesToReceive / 1024f) / 1024f).ToString("#0.##") + "mb"
+ " (" + e.ProgressPercentage + "%)");
}
private static string ExtractAndRename(int currentId)
{
//using SevenZipExtractor lib http://stackoverflow.com/questions/20898794/how-to-extract-files-in-my-archive-one-by-one-using-sevenzipsharp
SevenZipExtractor extractor = new SevenZipExtractor(@"d:'tmp'" + id.Name);
extractor.Extracting += extractor_Extracting;
extractor.ExtractArchive(@"d:'tmp'" + extractName[0]);
return (@"d:'tmp'" + extractName[0]);
}
public static void extractor_Extracting(object sender, SevenZip.ProgressEventArgs p)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("'b'b{0}% Extracted", p.PercentDone);
Console.ResetColor();
}
- 为每个线程提供一个变量
y
,其中包含允许写入的行号 在线程想要更新屏幕之前,创建一个锁。控制台一次只能由一个线程使用。否则多个线程的结果会混淆。 - 将光标移动到
y
指定的行并更新该行。 - 释放锁
一个例子:
static private readonly object _sync = new object();
private static void UpdateProgress(int y, string item, int progress, int total)
{
int percentage = (int)100.0 * progress / total;
lock(_sync)
{
Console.CursorLeft = 0;
Console.CursorTop = y;
Console.Write(item + " [" + new string('=', percentage / 2) + "] " + percentage + "%");
}
}
你可以从你的方法clientFileDownload
中调用这个方法,它必须被修改一点:
private static void clientFileDownload(int currentId, int y)
,在创建线程时应该像这样调用:
int y = 0;
Parallel.ForEach(FileIds, currentId =>
{
int currentId = FileIds.Id
clientFileDownload(currentId, y);
Interlocked.Increment(ref y);
});