如何上传到ftp多个文件并在多个progressBars上显示?

时间:2014-11-13 18:44:48

标签: c# .net winforms ftp

我的意思是,如果我为30个文件的上传提供一个列表,它将打开30个上传插槽将实时上传所有文件,因此我将看到30个progressBars,它将上传所有文件并行。

在form1设计器中,我已经有一个progressBar。

这是ftp上传的类代码:

using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;

namespace FTP_ProgressBar
{
    /// <summary>
    /// The FtpProgress class is derived from background worker, so it has the built-in functions of 
    /// run, report progress, and completed. 
    /// It only does upload, as a demonstration of how to transfer a file by FTP and report the progress. 
    /// </summary>
    public partial class FtpProgress : BackgroundWorker
    {
        public FtpProgress()
        {
            InitializeComponent();
        }

        public FtpProgress(IContainer container)
        {
            container.Add(this);
            InitializeComponent();
        }

        private void FtpProgress_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker bw = sender as BackgroundWorker;
            FtpSettings f = e.Argument as FtpSettings;
            // set up the host string to request.  this includes the target folder and the target file name (based on the source filename)
            string UploadPath = String.Format("{0}/{1}{2}", f.Host, f.TargetFolder == "" ? "" : f.TargetFolder + "/", Path.GetFileName(f.SourceFile));
            if(!UploadPath.ToLower().StartsWith("ftp://"))
                UploadPath = "ftp://" + UploadPath;
            FtpWebRequest request = (FtpWebRequest)WebRequest.Create(UploadPath);
            request.UseBinary = true;
            request.UsePassive = f.Passive;
            request.Method = WebRequestMethods.Ftp.UploadFile;
            request.Credentials = new NetworkCredential(f.Username, f.Password);

            // Copy the contents of the file to the request stream.
            long FileSize = new FileInfo(f.SourceFile).Length;
            string FileSizeDescription = GetFileSize(FileSize); // e.g. "2.4 Gb" instead of 240000000000000 bytes etc...            
            int ChunkSize = 4096, NumRetries = 0, MaxRetries = 50;
            long SentBytes = 0;
            byte[] Buffer = new byte[ChunkSize];    // this buffer stores each chunk, for sending to the web service via MTOM
            using(Stream requestStream = request.GetRequestStream())
            {
                using(FileStream fs = File.Open(f.SourceFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                {
                    int BytesRead = fs.Read(Buffer, 0, ChunkSize);  // read the first chunk in the buffer
                    // send the chunks to the web service one by one, until FileStream.Read() returns 0, meaning the entire file has been read.
                    while(BytesRead > 0)
                    {
                        try
                        {
                            if(bw.CancellationPending)
                                return;

                            // send this chunk to the server.  it is sent as a byte[] parameter, but the client and server have been configured to encode byte[] using MTOM. 
                            requestStream.Write(Buffer, 0, BytesRead);

                            // sentBytes is only updated AFTER a successful send of the bytes. so it would be possible to build in 'retry' code, to resume the upload from the current SentBytes position if AppendChunk fails.
                            SentBytes += BytesRead;

                            // update the user interface
                            string SummaryText = String.Format("Transferred {0} / {1}", GetFileSize(SentBytes), FileSizeDescription);
                            bw.ReportProgress((int)(((decimal)SentBytes / (decimal)FileSize) * 100), SummaryText);
                        }
                        catch(Exception ex)
                        {
                            Debug.WriteLine("Exception: " + ex.ToString());
                            if(NumRetries++ < MaxRetries)
                            {
                                // rewind the filestream and keep trying
                                fs.Position -= BytesRead;
                            }
                            else
                            {
                                throw new Exception(String.Format("Error occurred during upload, too many retries. \n{0}", ex.ToString()));
                            }
                        }
                        BytesRead = fs.Read(Buffer, 0, ChunkSize);  // read the next chunk (if it exists) into the buffer.  the while loop will terminate if there is nothing left to read
                    }
                }
            }
            using(FtpWebResponse response = (FtpWebResponse)request.GetResponse())
                System.Diagnostics.Debug.WriteLine(String.Format("Upload File Complete, status {0}", response.StatusDescription));
        }



        /// <summary>
        /// Returns a description of a number of bytes, in appropriate units.
        /// e.g. 
        ///     passing in 1024 will return a string "1 Kb"
        ///     passing in 1230000 will return "1.23 Mb"
        /// Megabytes and Gigabytes are formatted to 2 decimal places.
        /// Kilobytes are rounded to whole numbers.
        /// If the rounding results in 0 Kb, "1 Kb" is returned, because Windows behaves like this also.
        /// </summary>
        public static string GetFileSize(long numBytes)
        {
            string fileSize = "";

            if(numBytes > 1073741824)
                fileSize = String.Format("{0:0.00} Gb", (double)numBytes / 1073741824);
            else if(numBytes > 1048576)
                fileSize = String.Format("{0:0.00} Mb", (double)numBytes / 1048576);
            else
                fileSize = String.Format("{0:0} Kb", (double)numBytes / 1024);

            if(fileSize == "0 Kb")
                fileSize = "1 Kb";  // min.                         
            return fileSize;
        }
    }

    public class FtpSettings
    {
        public string Host, Username, Password, TargetFolder, SourceFile;
        public bool Passive;
        public int Port = 21;
    }
}

在form1:上传按钮点击事件:

private void btnUpload_Click(object sender, EventArgs e)
        {
            // the upload button is also used as a cancel button, depending on the state of the FtpProgress thread
            if(this.ftpProgress1.IsBusy)
            {
                this.ftpProgress1.CancelAsync();
                this.btnUpload.Text = "Upload";
            }
            else
            {
                // create a new FtpSettings class to store all the paramaters for the FtpProgress thread
                FtpSettings f = new FtpSettings();
                f.Host = this.txtHost.Text;
                f.Username = this.txtUsername.Text;
                f.Password = this.txtPassword.Text;
                f.TargetFolder = this.txtDir.Text;
                f.SourceFile = this.txtUploadFile.Text;
                f.Passive = this.chkPassive.Checked;
                try
                {
                    f.Port = Int32.Parse(this.txtPort.Text);
                }
                catch { }
                this.toolStripProgressBar1.Visible = true;
                this.ftpProgress1.RunWorkerAsync(f);
                this.btnUpload.Text = "Cancel";
            }
        }

Backgorundworker progresschanged:

private void ftpProgress1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.toolStripStatusLabel1.Text = e.UserState.ToString();   // the message will be something like: 45 Kb / 102.12 Mb
            this.toolStripProgressBar1.Value = Math.Min(this.toolStripProgressBar1.Maximum, e.ProgressPercentage);      
        }

完成的活动:

private void ftpProgress1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if(e.Error != null)
                MessageBox.Show(e.Error.ToString(), "FTP error");
            else if(e.Cancelled)
                this.toolStripStatusLabel1.Text = "Upload Cancelled";
            else
                this.toolStripStatusLabel1.Text = "Upload Complete";
            this.btnUpload.Text = "Upload";
            this.toolStripProgressBar1.Visible = false;
        }

在form1设计器中有一些文本框,我输入密码用户名ftp地址和要上传的文件。

这是用于上传的文件浏览器:

private void btnBrowse_Click(object sender, EventArgs e)
        {
            if(this.openFileDialog1.ShowDialog() != DialogResult.Cancel)
                this.txtUploadFile.Text = this.openFileDialog1.FileName;
        }

现在改为我希望能够选择多个文件的单个文件,如果我选择了多个文件,那么它将实时上传所选文件的数量。 如果我选择了2个文件,它将创建另一个新的progressBar,并将在文件上传的两个progressBars上显示。

如果我将选择34个文件,它将创建34个progressBars,并在其上显示上传进度。

1 个答案:

答案 0 :(得分:0)

一次浏览多个文件时,操作仅发生一次。即;所有选定的文件都将到达您指定的位置(服务器)。所以,这就是你只能看到一个进度条的原因。

如果您需要多个进度条,则应尝试放置多个按钮,以便通过每个按钮选择每个文件。