This project is read-only.

bytes already downloaded

Mar 21, 2012 at 1:40 PM

Hello,

I was wondering, is there any way to determine how many bytes are already downloaded with the SFTP class? I want to fill a progressBar based on how much of a file I already downloaded. While I know that I can get the file Lenght in bytes via the SftpFile class, I'm wondering how i can get the transferred bytes while downloading.

I would be grateful for some help and some code examples in c#

Mar 21, 2012 at 1:50 PM

Hi,

 

Yes, its possible, here is a code example that I used a while back.

var asynch = sftpClient.BeginDownloadFile(file, mem, null, null);
            var sftpAsynch = asynch as Renci.SshClient.Sftp.SftpAsyncResult;

            while (!sftpAsynch.IsCompleted)
            {
                Console.Write(String.Format("\rDownloaded {0} of {1}.", sftpAsynch.DownloadedBytes, 0));
            }
            sftpClient.EndDownloadFile(asynch);

Let me know if you having a problems with that.

 

Thanks,

Oleg

Mar 21, 2012 at 1:56 PM

Hi,

I take it, that you mean a Filestream with the variable "mem", or am I mistaken?

Mar 21, 2012 at 2:06 PM

well, in my case it was a memory stream but it could be any stream for that matter.

Mar 21, 2012 at 3:02 PM
Edited Mar 21, 2012 at 3:02 PM

Hi,

Will I hope this is my last problem with this (although I doubt that).

When I use your c ode and modify it so that I can loop through a list with filesi get the following error:

The type or namespace name 'SshClient' does not exist in the namespace 'Renci' (are you missing an assembly reference?)

and if I take away the Renci i get the following error:

The type name 'Sftp' does not exist in the type 'Renci.SshNet.SshClient'

 

I searched through the dll via object browser and found no "SftpAsyncResult" But i founf this one:

 SftpDownloadAsyncResult(System.AsyncCallback asyncCallback, object state)

Do i have to use this, or maybe another method?

Mar 21, 2012 at 3:08 PM

I think you right,

You probably need to use SftpDownloadAsyncResult.

 

I think the example I gave you was a little old and I split it into seperate classes since then.

Sorry about that.

 

Thanks,

Oleg

Mar 21, 2012 at 4:44 PM

no problem.

But I still have a problem I'm still new to programming and haven't worked with the Filestream/memorystream much. So I have no idea how to write the Downloaded bytes to the disk.  Below is the code of the class I use to download. I want to download the file via BackgroundDownloader so it doesn't freeze my UI Thread. While downloading the BackgroundDownloader should report the PrecentProgress and update the progressbarSingle control accordingly. After a single file was downloaded the BW_Run_Completed method increases the ProgressBarOverall by a certain (calculated) value, so that when the BackgroundWorker finishes both bars are at 100% and the download is complete.

Now my problem is the download part, everything else is working fine (although with place-holder methods and loops). I can only access the server via SFTP. And I don't want any downloading via HTTP (that's why i want to use SSH.net). I'm using the latest .NET 4.0 version of SSH.NET.

Thanks in advance for helping:

using System;
using System.ComponentModel;
using System.Windows.Forms;
using Renci.SshNet;
using Renci.SshNet.Sftp;
using System.Collections.Generic;
using System.IO;


namespace BKLauncher.Updates
{
    class Updates
    {
        BackgroundWorker Worker = new BackgroundWorker();
        public Form _Form { get; set; }
        public int NumberOfFiles { get; set; }

        //Connection details
        static string _Hostname = "my_host";
        static string _Username = "username";
        static string _Password = "password";

        #region BackgroundWorker Methods
        /// <summary>
        /// Creates the BackgroundWorker with WorkerReportsProgress and 
        /// WorkerSupportsCancellation set to true. 
        /// Also creates the three Eventhandlers
        /// </summary>
        public void CreateBackgroundWorker()
        {
            //Set WorkerReportsProgress and WorkerSupportsCancellation to true
            Worker.WorkerSupportsCancellation = true;
            Worker.WorkerReportsProgress = true;

            //Generate the EventHandler
            Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Worker_RunWorkerCompleted);
            Worker.ProgressChanged += new ProgressChangedEventHandler(Worker_ProgressChanged);
            Worker.DoWork += new DoWorkEventHandler(Worker_DoWork);

            Worker.RunWorkerAsync();
        }

        void Worker_DoWork(object sender, DoWorkEventArgs e)
        {
            //ToDo: Implement the download here.
            //For now use a placeholder for-loop
            for (int i = 0; i <= 2; i++)
            {
                Worker.ReportProgress(i * 50);
                System.Threading.Thread.Sleep(100);
            }

            //remove last, after code has been completed
            //throw new NotImplementedException();
        }

        void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //Create an instace of the single file progressBar
            ProgressBar ProgressBarSingle = ((ProgressBar)_Form.Controls["ProgressBarSingle"]);

            //Increase the value of the progressBar by e.ProgressPercentage
            ProgressBarSingle.Value = e.ProgressPercentage;
        }

        void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //Create the two ProgressBars for later.
            ProgressBar ProgressBarOverall = ((ProgressBar)_Form.Controls["progressBarOverall"]);
            ProgressBar ProgressBarSingle = ((ProgressBar)_Form.Controls["ProgressBarSingle"]);

            //Calculate by whic the Overall ProgressBar needs to be increased,
            //so that we get a smooth rise.
            int PercentRise = 100 / NumberOfFiles;

            //create the recursion and check for errors raised while runnning async.
            if (e.Error != null)
            {
                //Show the error message to the user.
                MessageBox.Show(e.Error.Message);
            }
            else if (ProgressBarOverall.Value >= 100)
            {
                //Duno why it has to be here, but if it isn't the progressBarSingle
                //doesn't stop working. So leave it here with no code...
            }
            else
            {
                //Set the SingleFile progressBar to 0, so it cann be filled again
                ProgressBarSingle.Value = 0;
                //This is the "catch" part, so the programm doesn't throw up an error
                if (ProgressBarOverall.Value + PercentRise >= 100)
                {
                    //Set both progress bars to 100 so it looks better.
                    ProgressBarOverall.Value = 100;
                    ProgressBarSingle.Value = 100;
                }
                else
                {
                    //increase the Global progressBar by the calculated amount for each file
                    ProgressBarOverall.Value = ProgressBarOverall.Value + PercentRise;
                }
                //Run the Worker again.
                Worker.RunWorkerAsync();
            }
        }
        #endregion

        public void DownloadLauncherFiles()
        {
            List<Files> Files = new List<Files>();
            Properties.Settings _settings = new Properties.Settings();

            //The path to start
            string RemotePath = "/Ruhrpottpatriot/launcher";

            using (SftpClient sftp = new SftpClient(_Hostname, _Username, _Password))
            {
                try
                {
                    sftp.Connect();

                    Files = Directories(Files, RemotePath, sftp);

                    CreateLocalFolderStructure(Files, _settings.DownloadPath);

                    for (int i = 0; i < Files.Count; i++)
                    {
                        string DownloadPath = RemotePath + Files[i].ParentDirectory;

                        FileStream mem = new FileStream(@"C:\temp\"+Files[i].Name, FileMode.Create);
                        
                        var async = sftp.BeginDownloadFile(DownloadPath + "/" + Files[i].Name, mem, null, null);

                        var sftpAsynch = async as Renci.SshNet.Sftp.SftpDownloadAsyncResult;
                        if (!Files[i].IsDirectory)
                        {
                            while (!sftpAsynch.IsCompleted)
                            {
                                string DlBytes = sftpAsynch.DownloadedBytes.ToString();
                                //I think the writing to disk needs to be put here.
                            }
                            sftp.EndDownloadFile(async);
                            MessageBox.Show(sftpAsynch.DownloadedBytes.ToString());
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
                finally
                {
                    sftp.Disconnect();
                }
            }
        }

        private static void CreateLocalFolderStructure(List<Files> Files, string dlpath)
        {
            for (int i = 0; i < Files.Count; i++)
            {
                if (Files[i].IsDirectory)
                {
                    //Create a new folder under the current active one
                    string PathToNewFolder = Path.Combine(dlpath + Files[i].ParentDirectory, Files[i].Name);
                    Directory.CreateDirectory(PathToNewFolder);
                }
            }
        }

        private static List<Files> Directories(List<Files> Files, string Path, SftpClient sftp, string ParentDirectory = "")
        {
            foreach (SftpFile File in sftp.ListDirectory(Path))
            {
                if (File.Name != "." && File.Name != "..")
                {
                    Files.Add(new Files(File.Name, File.Length, ParentDirectory, File.IsDirectory));
                    if (File.IsDirectory)
                    {
                        string Path2 = Path + "/" + File.Name;
                        Directories(Files, Path2, sftp, ParentDirectory + "/" + File.Name);                       
                    }
                }
            }
            return Files;
        }
    }

    public class Files
    {
        public string Name { get; set; }
        public double Length { get; set; }
        public string ParentDirectory { get; set; }
        public bool IsDirectory { get; set; }

        /// <summary>
        /// A list of all the files/folder in a specific location.
        /// </summary>
        /// <param name="Name">The name of the file/folder.</param>
        /// <param name="Length">The Size of a file/folder in bytes.</param>
        /// <param name="IsDirectory">Is it a folder or a file?</param>
        public Files(string Name, double Length, string ParentDirectory, bool IsDirectory)
        {
            this.Name = Name;
            this.Length = Length;
            this.ParentDirectory = ParentDirectory;
            this.IsDirectory = IsDirectory;
        }
    }
}

I'd be also grateful for any tips on how I can improve my coding skills.

 

Regards