0
votes

This is the method to download the files from ftp server:

public void DownloadFtpContent(object sender ,string file, string filesdirectories,string fn)
        {    
            try
            {     
                BackgroundWorker bw = sender as BackgroundWorker;
                string filenameonly = Path.GetFileName(file);
                string ftpdirectories = Path.Combine(ftpcontentdir, filesdirectories);
                string fileurl = "ftp://" + file;
                FtpWebRequest reqFTP;                
                reqFTP = (FtpWebRequest)FtpWebRequest.Create(fileurl);                                
                reqFTP.Credentials = new NetworkCredential(UserName, Password);
                reqFTP.UseBinary = true;
                reqFTP.UsePassive = true;
                reqFTP.KeepAlive = true;                
                reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
                reqFTP.Proxy = null;                 
                FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
                Stream responseStream = response.GetResponseStream();

                if (!Directory.Exists(ftpdirectories))
                {
                    Directory.CreateDirectory(ftpdirectories);
                }
                FileStream writeStream = new FileStream(ftpdirectories + "\\" + filenameonly, FileMode.Create);
                string fnn = ftpdirectories + "\\" + filenameonly;
                int Length = 2048;
                Byte[] buffer = new Byte[Length];
                int bytesRead = responseStream.Read(buffer, 0, Length);
                string SummaryText = String.Format("File Name {0} / {1}", "", filenameonly);
                while (bytesRead > 0)
                {
                    writeStream.Write(buffer, 0, bytesRead);
                    bytesRead = responseStream.Read(buffer, 0, Length);
                    var progress = bytesRead * 100.0 / writeStream.Length;
                    bw.ReportProgress((int)progress,SummaryText);
                }


                writeStream.Close();
                response.Close();
            }
            catch (WebException wEx)
            {

            }
        }
    }

The method get each time a file from form1 backgroundworker dowork event. Then i'm reporting to the backgroundworker each file download progress and also the file name:

while (bytesRead > 0)
                {
                    writeStream.Write(buffer, 0, bytesRead);
                    bytesRead = responseStream.Read(buffer, 0, Length);
                    var progress = bytesRead * 100.0 / writeStream.Length;
                    bw.ReportProgress((int)progress,SummaryText);
                }

And this is the backgroundworker prgoresschanged event:

private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.toolStripStatusLabel2.Text = e.UserState.ToString();
            this.toolStripProgressBar2.Value = Math.Min(this.toolStripProgressBar2.Maximum, e.ProgressPercentage);
        }

Reporting the file name is fine. But the progress of each file download is not working good.

Each time a file is downloading i see the green color in the progressBar moving sometimes to 10% then back to 0 sometimes to 35% then back to 0 sometimes to 40% then back to 0 all the time it's moving some and then back to 0 it's never getting to the end to 100%

The problems is either with the progresschanged event with the way i'm getting the report:

this.toolStripProgressBar2.Value = Math.Min(this.toolStripProgressBar2.Maximum, e.ProgressPercentage);

Or maybe in the download method the way i'm calculating and reporting to the progressBar:

var progress = bytesRead * 100.0 / writeStream.Length;
bw.ReportProgress((int)progress,SummaryText);

The SummaryText reporting is working fine the problem is with the progress variable i think.

1

1 Answers

3
votes

Your math problem is right here:

                writeStream.Write(buffer, 0, bytesRead);
                bytesRead = responseStream.Read(buffer, 0, Length);
                var progress = bytesRead * 100.0 / writeStream.Length;
                bw.ReportProgress((int)progress,SummaryText);

The return value from responseStream.Read is the number of bytes you read in that one read. It's not the total number of bytes read since you started reading from the file.

Also, dividing the number of bytes read by the total number written (i.e. writeStream.Length) isn't telling you anything useful.

If you want to update a progress bar, you have to know how many total bytes there are in the file, and how many total bytes you've read up to this point. So if the file is 1,000,000 bytes long, and you've read 450,000 bytes total, the progress would be 45% (i.e. 450000/1000000).

In your code, you have to get the file size from the FTP server. That's the total number of bytes you're going to download. Then you need keep track of how many bytes you've read up to this point. The basic idea is:

int totalBytesToBeRead = ??; // somehow get length. responseStream.Length doesn't work.
int totalBytesRead = 0;
int bytesRead = -1;
while (bytesRead != 0)
{
    bytesRead = responseStream.Read(...);
    // now add to the total
    totalBytesRead += bytesRead;
    var progress = totalBytesRead * 100.0 / totalBytesToRead;
}

Update

The problem appears to be that FtpWebRequest doesn't supply a ContentLength, so you need some other way to get the length. The only thing that comes to mind is to request the length up front by doing a separate FtpWebRequest with the GetFileSize method. See Get File Size On An FTP in C# for an example.