2016-08-08 1 views
2

Привет У меня есть программа, которая загружает и распаковывает файлы параллельно (в потоках). это консольное приложение, и я хочу показать индикатор выполнения каждой операции в каждом потоке. для например:Как использовать панель управления консолью на основе текста в многопоточном режиме C#

Файл 1 [========== 35%] 35MB из 100mb загруженных

Файл 2 [==== 20%] 20mb из 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(); 
} 
+0

Вам нужно будет указать, какая консоль вы показывали загрузку и обновляете эту строку с помощью новой. – BugFinder

ответ

1
  1. Обеспечить каждую нить с переменной y, который содержит номер строки, ей дают возможность писать.
  2. Перед тем, как поток хочет обновить экран, создайте блокировку. Консоль может использоваться только по одному потоку за раз. В противном случае результаты нескольких потоков будут перемешиваться.
  3. Переместите курсор в строку, указанную y, и обновите эту строку.
  4. Отпустите замок.

Пример:

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); 
}); 
+0

Как бы вы определяли позицию курсора каждый раз в каждом потоке? – AnujDubey

+0

Код скорректирован (не проверен). –