【问题标题】:Using Progress Bar With C# Console App在 C# 控制台应用程序中使用进度条
【发布时间】:2018-08-25 20:41:15
【问题描述】:

我想在我的 SFTP 下载中包含一个进度条,以便用户了解它只是一个大文件并且进度没有冻结/锁定。我偶然发现了this nuget 包,它看起来完全符合我的需要,但由于我使用的是 SFTP,我正在获取我正在下载的文件的总文件大小,我想更新基于进度条尽可能真实地了解已传输了多少文件。

如果我正确理解了这段代码 - 我只会提供一个“总滴答”计数,这与文件大小完全无关,因此进度指示将不准确。如何根据文件大小显示实际进度?

const int totalTicks = 10;
var options = new ProgressBarOptions
{
  ProgressCharacter = '─',
  ProgressBarOnBottom = true
};
using (var pbar = new ProgressBar(totalTicks, "Initial message", options))
{
  pbar.Tick(); //will advance pbar to 1 out of 10.
  //we can also advance and update the progressbar text
  pbar.Tick("Step 2 of 10"); 
}

编辑

经过一番谷歌搜索和大量试验和错误之后 - 我想出了下面的语法,它的功能几乎就像我想要的那样。我遇到的问题是进度条将仅显示第一个文件的进度,因此它将“密切”显示第一个文件的文件传输进度,当达到 100% 时它就坐在那里并且不会显示进度后续文件。

我需要更改以下代码中的哪些内容以显示从目录下载的所有文件的文件进度?

注意***以下代码中未声明的任何变量在我的代码中都声明为私有 const 变量

static void Main(string[] args)
{
    var options = new ProgressBarOptions
    {
        ProgressCharacter = '.',
        ProgressBarOnBottom = true
    };
    using (var pbar = new ProgressBar(totalTicks, "Starting To Download Files....", options))
        DownloadFile(spvalues.an, spvalues.lt, b, d, username, password, pbar, totalTicks, 500);    
}

private static void DownloadFile(string username, string password, ProgressBar pbar, int totalTicks, int sleep)
{
    for (int i = 0; i < totalTicks; i++)
    {
        Task.Delay(sleep).Wait();
        pbar.Tick(); 
    }
    using (var sftp = new SftpClient(Host, username, password))
    {
        sftp.Connect();
        string fullpath = RemoteDir + d + "/" + customer;
        var files = sftp.ListDirectory(fullpath);
        foreach (var file in files)
        {
            SftpFileAttributes att = sftp.GetAttributes(fullpath + "/" + file.Name);
            var fileSize = att.Size;
            var ms = new MemoryStream();
            IAsyncResult asyncr = sftp.BeginDownloadFile(fullpath + "/" + file.Name, ms);
            SftpDownloadAsyncResult sftpAsyncr = (SftpDownloadAsyncResult)asyncr;
            int lastpct = 0;
            while (!sftpAsyncr.IsCompleted)
            {
                int pct = (int)((long)sftpAsyncr.DownloadedBytes / fileSize) * 100;
                if (pct > lastpct)
                    for (int i = 1; i < pct - lastpct; i++)
                        pbar.Tick();
            }
            sftp.EndDownloadFile(asyncr);
            string localFilePath = "C:\\" + file.Name;
            var fs = new FileStream(localFilePath, FileMode.Create, FileAccess.Write);
            ms.WriteTo(fs);
            fs.Close();
            ms.Close();
        }
    }
}

【问题讨论】:

  • 看看这个:Copy directory files with progress bar。 (它写在VB.Net,但很容易翻译)。提供文件复制操作的可视化表示的控制台进度条。可以上色。
  • 尝试在 DownloadFile 方法的 foreach 循环中移动进度条实例。我认为问题在于您正在实例化一个进度条,但正在尝试使用 IAsyncResult 并且可能正在下载多个文件。这使进度条仅显示它在 foreach 循环中命中的第一个文件的进度。

标签: c# progress-bar console-application


【解决方案1】:

因为我认为没有其他人会帮助您解决这个问题:看看那个包装它看起来很漂亮,但是为了证明它仍然有效,这不是有点矫枉过正吗?现在,我可能不是 100% 的,但是你想要做的是使用线程。这意味着您可以让两个进程同时运行。一个线程将每隔一秒左右更新控制台,另一个线程将下载 SFTP 文件。下载 STFP 文件后,更新线程将被终止。

如果您想显示状态,那么在不知道您的代码的确切细节的情况下,我无法真正建议您,只能说您可以检查 Filestream 位置以获得总数的百分比。

状态线程会每秒更新一次,使用类似于:

public void foo()
{
    Task.Delay(1000).ContinueWith(t=> bar());
}

public void bar()
{
    // do stuff like check that the FileStream position has moved and change the console text
}

除此之外还有很多内容,我不会为您编写所有代码,但希望这可以为您指明一个方向(可能不是最好的)。

【讨论】:

  • 查看我的编辑 - 我发布了我尝试过的代码,这似乎接近您指向我的方向。你能解释一下我遇到的问题吗?
  • 从简单的看你的代码,你需要让它线程化,否则整个过程会挂起。 Task.Delay(sleep).Wait();将停止您的整个程序(我认为)。线程基本上意味着您有两件或多件事情同时发生。这个网站有一个教程。 tutorialspoint.com/csharp/csharp_multithreading.htm
  • 您需要一个线程来更新状态,而另一个线程来进行下载......我的错误。您有 IAsyncResult 以便为您完成工作。
猜你喜欢
  • 2014-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多