为什么当向进度栏报告每个文件下载的过程时,它永远不会达到 100%

本文关键字:永远 100% 过程 报告 文件下载 为什么 | 更新日期: 2023-09-27 18:33:49

这是从ftp服务器下载文件的方法:

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

该方法每次从 form1 后台工作线程执行工作事件获取文件。然后我向后台工作人员报告每个文件下载进度以及文件名:

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

这是后台工作者 prgoresschanged 事件:

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

报告文件名很好。但是每个文件下载的进度都不好。

每次下载文件时,我都会看到进度栏中的绿色有时移动到 10%,然后回到 0 有时移动到 35%,然后回到 0 有时到 40%,然后一直回到 0 它一直在移动一些然后回到 0 它永远不会到达 100%

问题出在进度更改事件和我获取报告的方式上:

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

或者也许在下载方法中,我计算并向进度栏报告的方式:

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

摘要文本报告工作正常,我认为问题出在进度变量上。

为什么当向进度栏报告每个文件下载的过程时,它永远不会达到 100%

你的数学问题就在这里:

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

responseStream.Read的返回值是您在该一次读取中读取的字节数。这不是自您开始读取文件以来读取的总字节数。

此外,将读取的字节数除以写入的总数(即 writeStream.Length(没有告诉你任何有用的东西。

如果要更新进度条,则必须知道文件中的总字节数,以及到目前为止已读取的总字节数。因此,如果文件长度为 1,000,000 字节,而您总共读取了 450,000 字节,则进度将为 45%(即 450000/1000000(。

在您的代码中,您必须从FTP服务器获取文件大小。这是您要下载的总字节数。然后,您需要跟踪到目前为止已读取的字节数。基本思想是:

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

更新

问题似乎是FtpWebRequest不提供ContentLength,所以你需要一些其他方法来获得长度。唯一想到的是通过使用GetFileSize方法进行单独的FtpWebRequest来预先请求长度。有关示例,请参阅在 C# 中获取 FTP 上的文件大小。