使用FtpWebRequest递归上传文件,C#中的BackgroundWorker

本文关键字:中的 BackgroundWorker 文件 FtpWebRequest 递归 使用 | 更新日期: 2023-09-27 18:28:58

使用FtpWebRequest类并分配BackgroundWorker上传文件。工作正常但现在我想从目录及其子目录上传文件。

我创建了一个名为-"FtpUploading"的组件,其中定义了私有的void函数"FtpUploading_DoWork"

同样应该是从windows窗体应用程序调用。。。如果目录中有单个文件,则工作文件,但如果有多个文件和子目录。。。它不会起作用。

    private void FtpUploading_DoWork(object sender, DoWorkEventArgs e)
    {
            BackgroundWorker bw = sender as BackgroundWorker;
            FtpSettings ftpDet = e.Argument as FtpSettings;
            string UploadPath = String.Format("{0}/{1}{2}", ftpDet.Host, ftpDet.TargetFolder == "" ? "" : ftpDet.TargetFolder + "/", Path.GetFileName(ftpDet.SourceFile));
            if (!UploadPath.ToLower().StartsWith("ftp://"))
                UploadPath = "ftp://" + UploadPath;
            FtpWebRequest request = (FtpWebRequest)WebRequest.Create(UploadPath);
            request.UseBinary = true;
            request.UsePassive = ftpDet.Passive;
            request.Method = WebRequestMethods.Ftp.UploadFile;
            request.Credentials = new NetworkCredential(ftpDet.Username, ftpDet.Password);
            long FileSize = new FileInfo(ftpDet.SourceFile).Length;
            string mFileName = new FileInfo(ftpDet.SourceFile).Name;
            string FileSizeDescription = GetFileSize(FileSize);
            int ChunkSize = 4096, NumRetries = 0, MaxRetries = 50;
            long SentBytes = 0;
            byte[] Buffer = new byte[ChunkSize];
            using (Stream requestStream = request.GetRequestStream())
            {
                using (FileStream fs = File.Open(ftpDet.SourceFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                {
                    int BytesRead = fs.Read(Buffer, 0, ChunkSize);  
                    while (BytesRead > 0)
                    {
                        try
                        {
                            if (bw.CancellationPending)
                                return;
                            requestStream.Write(Buffer, 0, BytesRead);
                            SentBytes += BytesRead;
                            string SummaryText = String.Format(mFileName + " => 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)
                            {
                                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);  
                    }
                }
            }
            using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
                System.Diagnostics.Debug.WriteLine(String.Format("Upload File Complete, status {0}", response.StatusDescription));
        }

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

//调用功能

        private void recursiveDirectory(string dirPath, string uploadPath)
    {
        string[] files = Directory.GetFiles(dirPath, "*.*");
        string[] subDirs = Directory.GetDirectories(dirPath);
        foreach (string file in files)
        {
            if (this.ftpUploading1.IsBusy)
            {
               // this.ftpUploading1.CancelAsync();
               // this.btnFtp.Text = "Upload";
                Thread.Sleep(50);
                break;
            }
            else
            {
                ftpSet.TargetFolder = uploadPath;
                ftpSet.SourceFile = file;
                this.toolStripProgressBar1.Visible = true;
                this.ftpUploading1.RunWorkerAsync(ftpSet);
                this.btnFtp.Text = "Cancel";
            }
        }
        foreach (string subDir in subDirs)
        {
            ftpClient.createDirectory(uploadPath + "/" + Path.GetFileName(subDir));
            recursiveDirectory(subDir, uploadPath + "/" + Path.GetFileName(subDir));
        }
    }

使用FtpWebRequest递归上传文件,C#中的BackgroundWorker

在启动aync任务后立即检查IsBusy,如果是true,则打破几乎总是这样的循环。

删除该条件将导致您在评论中提到的错误。因此,您应该等待任务完成,或者在FtpUploading_DoWork中实现一个循环。

第三种(也是最好的)选择是使用TaskTask支持ContinueWith(),这正是您所需要的。

我将在这里解释第一个解决方案,因为它只需要对现有代码进行很少的更改。此外,这只是为了让您了解同步过程。您可能需要进一步完善代码。

您需要一个WaitHandle,以便FtpUploading_DoWorkrecursiveDirectory完成其工作时告诉它。对于这件事,我们将使用ManualResetEvent。一旦您Reset手动重置事件,它将等待对WaitOne的调用,直到另一个线程在同一手动重置事件上调用Set

所以回到工作中,在你的类中添加一个ManualResetEvent

System.Threading.ManualResetEvent waitForUpload = new 
                               System.Threading.ManualResetEvent(false);

更改recursiveDirectory:内的第一个for

    foreach (string file in files)
    {
        ftpSet.TargetFolder = uploadPath;
        ftpSet.SourceFile = file;
        this.toolStripProgressBar1.Visible = true;
        waitForUpload.Reset();
        this.ftpUploading1.RunWorkerAsync(ftpSet);
        this.btnFtp.Text = "Cancel";
        waitForUpload.WaitOne();
        while (this.ftpUploading1.IsBusy)
        {
            Thread.Sleep(100); // This is for the case if the WaitHandle is Set
                               // but the BackgroundWorker is still busy, 
                               // which should not take so long
        }
    }

并更改FtpUploading_DoWork:

private void FtpUploading_DoWork(object sender, DoWorkEventArgs e)
{
    try
    {
         // Existing code inside the method
    }
    finally
    {
        waitForUpload.Set();
    }
}