2013-08-26 4 views
2

Использование класса FtpWebRequest и назначение BackgroundWorker для загрузки файла. И правильно работает , но теперь я хочу загрузить файлы из каталога и их подкаталога.Рекурсивная загрузка файлов с использованием FtpWebRequest, BackgroundWorker в C#

Я создал компонент под названием - «FtpUploading», в котором определить функцию собственной недействительным «FtpUploading_DoWork»

И то же самое должно быть призывающую из окна формы приложения ... Если один файл в каталоге, то рабочий файл, но если есть более одного файла и подкаталога ... это не сработает.

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

«это будет не работает "- не очень хороший отчет о проблеме. Включите полные сообщения об ошибках и/или опишите, что на самом деле происходит против ожидаемого. –

+0

Он загружает только один файл, и если я не проверял IsBusy, тогда «этот BackgroundWorker в настоящее время занят и не может одновременно запускать несколько задач». И я хочу, чтобы после завершения первой задачи была назначена следующая задача. Новая задача будет назначаться после сообщения «ftpUploading1_RunWorkerCompleted». – user2717440

ответ

0

Вы проверить IsBusy сразу после запуска задачи aync, и если это true, вы разорвать петлю, которая из почти всегда есть. Это то, что происходит.

Удаление этого условия приведет к ошибке, упомянутой в комментариях. Поэтому вам нужно либо дождаться завершения задачи, либо реализовать цикл внутри FtpUploading_DoWork.

И третий (и лучший) вариант заключается в использовании Task. Task поддерживает ContinueWith(), что именно то, что вам нужно.

Здесь я объясню первое решение, потому что для вашего существующего кода требуется очень мало изменений. Кроме того, это просто, чтобы дать вам представление о процессе синхронизации. Вам, вероятно, придется отполировать код дальше.

Вам нужно WaitHandle, для FtpUploading_DoWork, чтобы сообщить recursiveDirectory, когда оно закончит свою работу. Мы будем использовать ManualResetEvent по этому вопросу. Как только вы Reset ManualResetEvent, он будет ждать по вызову WaitOne, пока другой поток не вызовет Set на том же самом ManualResetEvent.

Итак, вернемся к работе, добавить ManualResetEvent к классу:

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

Измените первый for внутри recursiveDirectory:

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