FtpWebRequest带有进度条的FTP下载

3
我的代码可以正常工作,但是进度条会直接跳到100%,然后下载会继续。当下载完成之后,会出现一个消息框来提示信息。
我已经更改了缓冲区大小,但是没有用。
我在这里做错了什么?
下面是我的代码:
void workerDOWN_DoWork(object sender, DoWorkEventArgs e)
{
    string fileFullPath = e.Argument as String;
    string fileName = Path.GetFileName(fileFullPath);
    string fileExtension = Path.GetExtension(fileName);

    label4.Invoke((MethodInvoker)delegate { label4.Text = "Downloading File.."; });

    string ftpServerIP = "XXX";
    string ftpUserName = "XXX";
    string ftpPassword = "XXX";

    try
    {
        //Datei vom FTP Server downloaden
        FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://" + ftpServerIP + "/" + fileName);
        request.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
        request.Method = WebRequestMethods.Ftp.DownloadFile;
        using (Stream ftpStream = request.GetResponse().GetResponseStream())
        using (Stream fileStream = File.Create(fileFullPath))
        {
            var buffer = new byte[32 * 1024];
            int totalReadBytesCount = 0;
            int readBytesCount;
            while ((readBytesCount = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
            {
                fileStream.Write(buffer, 0, readBytesCount);
                totalReadBytesCount += readBytesCount;
                var progress = (int)((float)totalReadBytesCount / (float)fileStream.Length * 100);
                workerDOWN.ReportProgress((int)progress);
                label3.Invoke((MethodInvoker)delegate { label3.Text = progress + " %"; });
            }
        }
    }
    catch (WebException ex)
    {
        FtpWebResponse response = (FtpWebResponse)ex.Response;

        if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
        {
            MessageBox.Show("Datei nicht gefunden!", "Error");
        }
    }
    e.Result = fileFullPath;
}


void workerDOWN_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
     string fileFullPath = e.Result as String;
     string fileName = Path.GetFileName(fileFullPath);

     MessageBox.Show("Download erfolgreich!","Information");

     progressBar1.Value = 0;
     label3.Invoke((MethodInvoker)delegate { label3.Text = " "; });
     label4.Invoke((MethodInvoker)delegate { label4.Text = " "; });      
}
3个回答

4

使用WinForms进度条的FTP下载的简单示例,使用FtpWebRequest

private void button1_Click(object sender, EventArgs e)
{
    // Run Download on background thread
    Task.Run(() => Download());
}

private void Download()
{
    try
    {
        const string url = "ftp://ftp.example.com/remote/path/file.zip";
        var credentials = new NetworkCredential("username", "password");

        // Query size of the file to be downloaded
        WebRequest sizeRequest = WebRequest.Create(url);
        sizeRequest.Credentials = credentials;
        sizeRequest.Method = WebRequestMethods.Ftp.GetFileSize;
        int size = (int)sizeRequest.GetResponse().ContentLength;

        progressBar1.Invoke(
            (MethodInvoker)(() => progressBar1.Maximum = size));
        
        // Download the file
        WebRequest request = WebRequest.Create(url);
        request.Credentials = credentials;
        request.Method = WebRequestMethods.Ftp.DownloadFile;

        using (Stream ftpStream = request.GetResponse().GetResponseStream())
        using (Stream fileStream = File.Create(@"C:\local\path\file.zip"))
        {
            byte[] buffer = new byte[10240];
            int read;
            while ((read = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
            {
                fileStream.Write(buffer, 0, read);
                int position = (int)fileStream.Position;
                progressBar1.Invoke(
                    (MethodInvoker)(() => progressBar1.Value = position));
            }
        }
    }
    catch (Exception e)
    {
        MessageBox.Show(e.Message);
    }
}

enter image description here

核心下载代码基于:
C#/.NET中上传和下载文件到/从FTP服务器
为了说明你的代码为什么不起作用:
  • 你正在使用目标文件的大小进行计算:fileStream.Length - 它始终等于totalReadBytesCount,因此progress将始终为100。
  • 你可能想使用ftpStream.Length,但是它无法读取。
  • 基本上,使用FTP协议时,你不知道你正在下载的文件的大小。如果需要知道它,你必须在下载前明确查询它。这里我使用WebRequestMethods.Ftp.GetFileSize来查询。

1
我现在有一个适合我的解决方案。
首先获取文件大小的想法很棒。 但是当我第一次查询文件大小时,FTP服务器会抛出错误。就像这样 FtpWebRequest error: 550 Size not allowed in ASCII mode 现在我先下载一个虚拟文件来打开连接。请参见下文。
感谢所有人的支持。
伟大的社区。谢谢。
void workerDOWN_DoWork(object sender, DoWorkEventArgs e)
        {
            string fileFullPath = e.Argument as String;
            string fileName = Path.GetFileName(fileFullPath);
            string fileExtension = Path.GetExtension(fileName);

            label4.Invoke((MethodInvoker)delegate { label4.Text = "Downloading File.."; });

            //FTP Download und Delete
            string ftpServerIP = "XXX";
            string ftpUserName = "XXXX";
            string ftpPassword = "XXXXX";

            try
            {
                // dummy download ftp connection for ftp server bug
                FtpWebRequest DummyRequest = (FtpWebRequest)WebRequest.Create(("ftp://" + ftpServerIP + "/anyfile"));
                DummyRequest.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
                DummyRequest.Method = WebRequestMethods.Ftp.DownloadFile;
                using (Stream ftpStream = DummyRequest.GetResponse().GetResponseStream())
                using (Stream fileStream = File.Create(Path.GetDirectoryName(Application.ExecutablePath) + "\\anyfile"))
                {
                    ftpStream.CopyTo(fileStream);
                }
                //delete downloaded test file
                File.Delete(Path.GetDirectoryName(Application.ExecutablePath) + "\\anyfile");

                // Query size of the file to be downloaded
                FtpWebRequest sizeRequest = (FtpWebRequest)WebRequest.Create("ftp://" + ftpServerIP + "/" + fileName);
                sizeRequest.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
                sizeRequest.Method = WebRequestMethods.Ftp.GetFileSize;
                var fileSize = sizeRequest.GetResponse().ContentLength;

                //file download
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://" + ftpServerIP + "/" + fileName);
                request.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
                request.Method = WebRequestMethods.Ftp.DownloadFile;
                using (Stream ftpStream = request.GetResponse().GetResponseStream())
                using (Stream fileStream = File.Create(fileFullPath))
                {
                    var buffer = new byte[32 * 1024];
                    int totalReadBytesCount = 0;
                    int readBytesCount;
                    while ((readBytesCount = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        fileStream.Write(buffer, 0, readBytesCount);
                        totalReadBytesCount += readBytesCount;
                        var progress = (int)((float)totalReadBytesCount / (float)fileSize * 100);
                        workerDOWN.ReportProgress((int)progress);
                        label3.Invoke((MethodInvoker)delegate { label3.Text = progress + " %"; });
                    }
                }

                // delete file on ftp server
                FtpWebRequest Delrequest = (FtpWebRequest)WebRequest.Create("ftp://" + ftpServerIP + "/" + fileName);
                Delrequest.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
                Delrequest.Method = WebRequestMethods.Ftp.DeleteFile;
                FtpWebResponse Delresponse = (FtpWebResponse)Delrequest.GetResponse();
                Delresponse.Close();

                // message file deleted
                richTextBox1.Invoke((MethodInvoker)delegate { richTextBox1.AppendText("System: " + fileName + " wurde auf dem Server gelöscht." + Environment.NewLine); });

            }
            catch (WebException ex)
            {
                FtpWebResponse response = (FtpWebResponse)ex.Response;

                if (response.StatusCode == FtpStatusCode.ActionNotTakenFileUnavailable)
                {

                    MessageBox.Show("Datei nicht gefunden!", "Error");
                } 
            }

            e.Result = fileFullPath;

        }


        void workerDOWN_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;
        }

        void workerDOWN_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
             string fileFullPath = e.Result as String;
             string fileName = Path.GetFileName(fileFullPath);

             MessageBox.Show("Download erfolgreich!","Information");

             progressBar1.Value = 0;
             label3.Invoke((MethodInvoker)delegate { label3.Text = " "; });
             label4.Invoke((MethodInvoker)delegate { label4.Text = " "; });


        }

0

不知道您在 ProgressChanged 事件处理程序中的代码具体是做什么的,我认为您在进度计算中无意中将括号放在了 * 100 之后。

您可以尝试这个:

var progress = (int)((float)totalReadBytesCount / (float)fileStream.Length) * 100;

我假设那是你提到的更新进度条的地方。(参见:https://msdn.microsoft.com/zh-cn/library/system.componentmodel.backgroundworker.reportprogress(v=vs.110).aspx) -- ReportProgress会引发该事件。 - Dick Appel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接