Thanh tiến trình trong ứng dụng bảng điều khiển


82

Tôi đang viết một ứng dụng bảng điều khiển c # đơn giản để tải tệp lên máy chủ sftp. Tuy nhiên, số lượng tệp lớn. Tôi muốn hiển thị phần trăm tệp đã tải lên hoặc chỉ số tệp đã tải lên từ tổng số tệp sẽ tải lên.

Đầu tiên, tôi lấy tất cả các tệp và tổng số tệp.

string[] filePath = Directory.GetFiles(path, "*");
totalCount = filePath.Length;

Sau đó, tôi lặp qua tệp và tải lên từng tệp một trong vòng lặp 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);
}

Trong vòng lặp foreach, tôi có một thanh tiến trình mà tôi gặp sự cố. Nó không hiển thị đúng.

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
}

Đầu ra chỉ là [] 0 trong số 1943

Tôi làm gì sai ở đây?

BIÊN TẬP:

Tôi đang cố hiển thị thanh tiến trình trong khi tải và xuất các tệp XML. Tuy nhiên, nó đi qua một vòng lặp. Sau khi kết thúc vòng đầu tiên, nó chuyển sang vòng thứ hai, v.v.

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

Nó không bao giờ rời khỏi vòng lặp for ... Bất kỳ đề xuất nào?


XmlCount và số lượng là gì?
eddie_cat

Chỉ đếm gia số. xmlCount chỉ là tổng số tệp XML trong thư mục được chỉ định DirectoryInfo xmlDir = new DirectoryInfo (xmlFullpath); xmlCount = xmlDir.GetFiles (). Chiều dài;
smr5,

1
Ngoài ra, tại sao vòng lặp for lại nằm trong vòng lặp foreach? Nó dường như đang lặp lại cùng một thứ. Có lẽ không cần thiết phải giữ vòng lặp foreach.
eddie_cat

1
Bạn đã loại bỏ vòng lặp foreach bên ngoài? Sự thay đổi các bit nhận xét đểExportXml(xmlFilePath[i])
eddie_cat

1
Điều đó là vậy đó. Tôi chỉ có vòng lặp for và nó hoạt động.
smr5,

Câu trả lời:


10

Dòng này là vấn đề của bạn:

drawTextProgressBar(0, totalCount);

Bạn đang nói rằng tiến độ là 0 trong mỗi lần lặp, điều này sẽ được tăng dần. Có thể sử dụng vòng lặp for để thay thế.

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

Nó hoạt động lần đầu tiên và tôi đang làm điều tương tự ở nơi khác trong cùng một lần và nó gây ra vòng lặp. Nó không bao giờ dừng lại. Tôi đã cập nhật bài viết của mình. Bạn có thể nhìn vào nó? Cảm ơn.
smr5,

Bạn đã cập nhật những gì? Tôi trông giống nhau, tôi còn thiếu cái gì?
eddie_cat

195

Tôi cũng đang tìm kiếm một thanh tiến trình bảng điều khiển. Tôi không tìm thấy một cái nào phù hợp với những gì tôi cần, vì vậy tôi quyết định tự làm. Nhấp vào đây để biết mã nguồn (Giấy phép MIT).

Thanh tiến trình hoạt ảnh

Đặc trưng:

  • Hoạt động với đầu ra được chuyển hướng

    Nếu bạn chuyển hướng đầu ra của ứng dụng bảng điều khiển (ví dụ Program.exe > myfile.txt:), hầu hết các triển khai sẽ bị lỗi với một ngoại lệ. Đó là bởi vì Console.CursorLeftConsole.SetCursorPosition()không hỗ trợ đầu ra được chuyển hướng.

  • Triển khai IProgress<double>

    Điều này cho phép bạn sử dụng thanh tiến trình với các hoạt động không đồng bộ báo cáo tiến trình trong phạm vi [0..1].

  • An toàn chủ đề

  • Nhanh

    Các Consolelớp học là khét tiếng cho hiệu suất không đáy của nó. Quá nhiều cuộc gọi đến nó và ứng dụng của bạn chạy chậm lại. Lớp này chỉ thực hiện 8 cuộc gọi mỗi giây, bất kể bạn có báo cáo cập nhật tiến độ thường xuyên hay không.

Sử dụng nó như thế này:

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.");

3
Cái này trông khá gọn gàng! Bạn có cân nhắc thêm giấy phép OSS như MIT vào nó không? selectalicense.com
Daniel Plaisted

2
Ý tưởng tốt. Xong rồi đó.
Daniel Wolf,

@DanielWolf làm cách nào để bạn có được Console.Write từ việc thay đổi CursorPosition?
JJS

1
@knocte: Trong mã sản xuất, tôi chắc chắn sẽ làm như vậy. Mục tiêu ở đây là giữ cho ví dụ ngắn gọn nhất có thể và không làm phân tán các phần liên quan.
Daniel Wolf,

8
Ảnh gif hấp dẫn.
Lei Yang

16

Tôi biết đây là một chủ đề cũ, và lời xin lỗi cho việc thúc đẩy tự, tuy nhiên gần đây tôi đã viết một nguồn giao diện điều khiển thư viện mở sẵn trên NuGet Goblinfactory.Konsole với thread hỗ trợ nhiều thanh tiến trình, có thể giúp bất cứ ai mới trang này cần một mà không chặn luồng chính.

Nó hơi khác với các câu trả lời ở trên vì nó cho phép bạn bắt đầu tải xuống và các tác vụ song song và tiếp tục với các tác vụ khác;

chúc mừng, hy vọng điều này là hữu ích

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.");

cung cấp cho bạn loại đầu ra này

nhập mô tả hình ảnh ở đây

Gói nuget cũng bao gồm các tiện ích để ghi vào phần cửa sổ của bảng điều khiển với hỗ trợ cắt và gói đầy đủ, cùng với PrintAtnhiều lớp hữu ích khác.

Tôi đã viết gói nuget vì tôi liên tục viết rất nhiều quy trình giao diện điều khiển phổ biến bất cứ khi nào tôi viết các tập lệnh và tiện ích giao diện điều khiển xây dựng và hoạt động.

Nếu tôi đang tải xuống một số tệp, tôi thường truy cập từ từ Console.Writevào màn hình trên mỗi chuỗi và thường thử các thủ thuật khác nhau để giúp đọc kết quả xen kẽ trên màn hình dễ đọc hơn, ví dụ như các màu hoặc số khác nhau. Cuối cùng tôi đã viết thư viện cửa sổ để đầu ra từ các luồng khác nhau có thể đơn giản được in ra các cửa sổ khác nhau và nó cắt giảm hàng tấn mã soạn sẵn trong các tập lệnh tiện ích của tôi.

Ví dụ, mã này,

        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

sản xuất cái này

nhập mô tả hình ảnh ở đây

Bạn cũng có thể tạo thanh tiến trình bên trong cửa sổ dễ dàng như ghi vào cửa sổ. (trộn và kết hợp).


Điều này là tốt nhất
Pratik

9

Bạn có thể muốn thử https://www.nuget.org/packages/ShellProgressBar/

Tôi vừa tình cờ triển khai thanh tiến trình này - nền tảng chéo của nó, thực sự dễ sử dụng, có thể định cấu hình khá tốt và thực hiện đúng những gì cần thiết.

Chỉ chia sẻ vì tôi thích nó rất nhiều.


6

Tôi đã sao chép ProgressBarphương pháp của bạn . Vì lỗi của bạn nằm trong vòng lặp như câu trả lời được chấp nhận đã đề cập. Nhưng ProgressBarphương pháp này cũng có một số lỗi cú pháp. Đây là phiên bản làm việc. Đã sửa đổi một chút.

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
}

Xin lưu ý rằng @ Daniel-wolf có cách tiếp cận tốt hơn: https://stackoverflow.com/a/31193455/169714


5

Tôi khá thích thanh tiến trình của áp phích gốc, nhưng nhận thấy rằng nó không hiển thị tiến trình một cách chính xác với các kết hợp tiến trình / tổng số mục nhất định. Ví dụ: phần sau không được vẽ chính xác, để lại thêm một khối màu xám ở cuối thanh tiến trình:

drawTextProgressBar(4114, 4114)

Tôi đã thực hiện lại một số mã vẽ để loại bỏ vòng lặp không cần thiết, điều này đã khắc phục sự cố ở trên và cũng đẩy nhanh mọi thứ lên khá nhiều:

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
}

Điều này nói chung hoạt động ngoại trừ việc nó xóa các đầu ra bảng điều khiển trước đó giống như bất kỳ văn bản nào trước đó và nó không chuyển sang dòng mới sau ....
David Shnayder

5

Tôi đã tạo lớp tiện dụng này hoạt động với System.Reactive. Tôi hy vọng bạn thấy nó đủ đáng yêu.

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();
    }
}

0

Tôi chỉ tình cờ phát hiện ra chuỗi này đang tìm kiếm thứ gì đó khác và tôi nghĩ rằng tôi sẽ bỏ mã của mình mà tôi tập hợp lại để tải xuống Danh sách tệp bằng cách sử dụng DownloadProgressChanged. Tôi thấy điều này cực kỳ hữu ích vì vậy tôi không chỉ nhìn thấy tiến trình mà còn cả kích thước thực tế khi tệp đang chạy qua. Hy vọng nó sẽ giúp một ai đó!

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)
    {
    }

Đây là một ví dụ về đầu ra: nhập mô tả hình ảnh ở đây

Hy vọng nó sẽ giúp một ai đó!


2
@regisbsb Đó không phải là thanh tiến trình, có vẻ như anh ấy đã kiểm duyệt một phần tên tệp :) Tôi biết, lúc đầu tôi cũng bị lừa.
silkfire

-1

Tôi vẫn còn một chút mới mẻ C#nhưng tôi tin rằng những điều dưới đây có thể hữu ích.

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++;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.