0
votes

I want to include a progress bar in my SFTP download so that the user understands it's just a large file and the progress hasn't frozen/locked up. I stumbled up on this nuget package that looks like it's doing exactly what I need, but since I am using SFTP I'm grabbing the total file size of the file I'm downloading and I would like to update the progress bar based as realistic as can be on how much of the file has been transferred.

If I understand this code properly - I would just provide a "total tick" count, which is totally unrelated to the file size so progress indication would not be accurate. How can I show the actual progress based on the file size?

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

edit

After some googling and a whole lot of trial and error - I have come up with the below syntax which functions almost like I want. The issue that I have is that the progress bar will show progress for the FIRST file only, so it will "closely" display the file transfer progress of the first file and when that reaches 100% it just sits there and will not show progress for subsequent files.

What in my below code do I need to change that will show the file progress of ALL files that are being downloaded from the directory?

NOTE***any variables not declared in the below code are declared as private const variables in my code

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();
        }
    }
}
1
Take a look at this:Copy directory files with progress bar. (It's written in VB.Net, but very easy to translate). A Console progress bar which gives a visual representation of a file copy operation. Could be colored. - Jimi
Try moving the progress bar instantiation inside your foreach loop in the DownloadFile method. I think the issue is that you are instantiating ONE progress bar, but are attempting to use IAsyncResult and could potentially be downloading multiple files. Which leaves the progress bar to only show progress for the first file that it hits in your foreach loop. - Bob Goblin

1 Answers

0
votes

Since I don't think anyone else is going to help you with this: looking at that package it looks beautiful but isn't that a bit of overkill just to prove that its still working? Now, I might not be 100% on this, however what you want to do is to use threading. This will mean that you can have the two processes running simultaneously. One thread will be updating the console ever second or so and the other would be downloading the SFTP file. Once the STFP file has downloaded the update thread would be killed.

If you want to show the status, then without knowing the exact details of your code I cant really advise you but to say that you could check the Filestream position to get a percent of the total.

The status thread would update every second using something similar to:

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
}

There's a lot more to it than this and Im not going to write all the code for you but hopefully that points you in a direction (possibly not the best one).