2009-08-14 5 views
9

Как я могу реализовать FileSystemWatcher для местоположения FTP (на C#). Идея - всякий раз, когда что-либо добавляется в место FTP, я хочу скопировать его на локальный компьютер. Любые идеи будут полезны.FileSystemWatcher для FTP

Это продолжение моего предыдущего вопроса Selective FTP download using .NET.

+0

Вы собираетесь использовать подход типа опроса. Вы должны периодически проверять сайт ftp, чтобы проверить, есть ли новый файл. – jersoft

ответ

14

Вам понадобится реализовать опрос, где вы периодически будете запрашивать содержимое каталога. Сравните это с кэшированным списком из предыдущего вызова и определите, что произошло в этом случае.

В протоколе FTP ничего нет, что поможет вам с этим, к сожалению.

3

Напишите простой сервис для создания FileSystemWatcher, указывая на ваше местоположение ftp.

Затем, когда файл загружен или изменен, в вашей службе будет запущено событие, которое вы можете использовать для копирования файла на локальный компьютер.
File.Copy т.д.

Hav посмотреть на: this blog

+0

Работает ли 'FileSystemWatcher' с URL-адресами? –

+0

Местоположение UNC, а не URL. – Bravax

7

The FileSystemWatcher класса работ по регистрации событий с принимающей операционной системой Windows. Таким образом, он ограничен работой локальных путей и путей UNC к каталогам, размещенным в системах Windows. В документации MSDN по адресу FileSystemWatcher объясняются пути, которые вы можете использовать, и некоторые из потенциальных проблем с использованием класса.

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

0

Способ, которым я обрабатываю это, - загрузить массив байтов с одним элементом, названный «.ftpComplete». FileSystemWatcher наблюдает только за файлами «.ftpComplete» и заставляет их отключать, чтобы узнать фактический загруженный файл. Так как файл «.ftpComplete» только один байт, он загружает примерно так же быстро, как она создается на FTP-сервере, так что он может быть удален, как только вы сделаете все, что вам нужно с основной Загруженный файл

 FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(
      FTPAddress + "/" + Path.GetFileName(filePath) + ".ftpComplete"); 
     request.Method = WebRequestMethods.Ftp.UploadFile; 
     request.Credentials = new NetworkCredential(username, password); 
     request.UsePassive = true; 
     request.UseBinary = true; 
     request.KeepAlive = false; 
     byte[] buffer = new byte[1]; 
     Stream reqStream = request.GetRequestStream(); 
     reqStream.Write(buffer, 0, buffer.Length); 
     reqStream.Close(); 
2

Вы можете отслеживать местоположение FTP по следующему методу:

public class FtpFileSystemWatcher 
{ 

    public bool IsRunning 
    { 
     get; 
     private set; 
    } 
    public string FtpUserName 
    { 
     get; 
     set; 
    } 
    public string FtpPassword 
    { 
     get; 
     set; 
    } 
    public string FtpLocationToWatch 
    { 
     get; 
     set; 
    } 
    public string DownloadTo 
    { 
     get; 
     set; 
    } 
    public bool KeepOrignal 
    { 
     get; 
     set; 
    } 
    public bool OverwriteExisting 
    { 
     get; 
     set; 
    } 
    public int RecheckIntervalInSeconds 
    { 
     get; 
     set; 
    } 
    private bool DownloadInprogress 
    { 
     get; 
     set; 
    } 

    private System.Timers.Timer JobProcessor; 

    public FtpFileSystemWatcher(string FtpLocationToWatch = "", string DownloadTo = "", int RecheckIntervalInSeconds = 1, string UserName = "", string Password = "", bool KeepOrignal = false, bool OverwriteExisting = false) 
    { 
     this.FtpUserName = UserName; 
     this.FtpPassword = Password; 
     this.FtpLocationToWatch = FtpLocationToWatch; 
     this.DownloadTo = DownloadTo; 
     this.KeepOrignal = KeepOrignal; 
     this.RecheckIntervalInSeconds = RecheckIntervalInSeconds; 
     this.OverwriteExisting = OverwriteExisting; 

     if (this.RecheckIntervalInSeconds < 1) this.RecheckIntervalInSeconds = 1; 
    } 

    public void StartDownloading() 
    { 

     JobProcessor = new Timer(this.RecheckIntervalInSeconds * 1000); 
     JobProcessor.AutoReset = false; 
     JobProcessor.Enabled = false; 
     JobProcessor.Elapsed += (sender, e) => 
     { 
      try 
      { 

       this.IsRunning = true; 

       string[] FilesList = GetFilesList(this.FtpLocationToWatch, this.FtpUserName, this.FtpPassword); 

       if (FilesList == null || FilesList.Length < 1) 
       { 
        return; 
       } 

       foreach (string FileName in FilesList) 
       { 
        if (!string.IsNullOrWhiteSpace(FileName)) 
        { 
         DownloadFile(this.FtpLocationToWatch, this.DownloadTo, FileName.Trim(), this.FtpUserName, this.FtpPassword, this.OverwriteExisting); 

         if (!this.KeepOrignal) 
         { 
          DeleteFile(Path.Combine(this.FtpLocationToWatch, FileName.Trim()), this.FtpUserName, this.FtpPassword); 
         } 
        } 
       } 

       this.IsRunning = false; 
       JobProcessor.Enabled = true;      
      } 

      catch (Exception exp) 
      { 
       this.IsRunning = false; 
       JobProcessor.Enabled = true; 
       Console.WriteLine(exp.Message); 
      } 
     }; 

     JobProcessor.Start(); 
    } 

    public void StopDownloading() 
    { 
     try 
     { 
      this.JobProcessor.Dispose(); 
      this.IsRunning = false; 
     } 
     catch { } 
    } 

    private void DeleteFile(string FtpFilePath, string UserName, string Password) 
    { 
     FtpWebRequest FtpRequest; 
     FtpRequest = (FtpWebRequest)FtpWebRequest.Create(new Uri(FtpFilePath)); 
     FtpRequest.UseBinary = true; 
     FtpRequest.Method = WebRequestMethods.Ftp.DeleteFile; 

     FtpRequest.Credentials = new NetworkCredential(UserName, Password); 
     FtpWebResponse response = (FtpWebResponse)FtpRequest.GetResponse(); 
     response.Close(); 

    } 
    private void DownloadFile(string FtpLocation, string FileSystemLocation, string FileName, string UserName, string Password, bool OverwriteExisting) 
    { 
     try 
     { 
      const int BufferSize = 2048; 
      byte[] Buffer = new byte[BufferSize]; 

      FtpWebRequest Request; 
      FtpWebResponse Response; 

      if (File.Exists(Path.Combine(FileSystemLocation, FileName))) 
      { 
       if (OverwriteExisting) 
       { 
        File.Delete(Path.Combine(FileSystemLocation, FileName)); 
       } 
       else 
       { 
        Console.WriteLine(string.Format("File {0} already exist.", FileName)); 
        return; 
       } 
      } 

      Request = (FtpWebRequest)FtpWebRequest.Create(new Uri(Path.Combine(FtpLocation, FileName))); 
      Request.Credentials = new NetworkCredential(UserName, Password); 
      Request.Proxy = null; 
      Request.Method = WebRequestMethods.Ftp.DownloadFile; 
      Request.UseBinary = true; 

      Response = (FtpWebResponse)Request.GetResponse(); 

      using (Stream s = Response.GetResponseStream()) 
      { 
       using (FileStream fs = new FileStream(Path.Combine(FileSystemLocation, FileName), FileMode.CreateNew, FileAccess.ReadWrite)) 
       { 
        while (s.Read(Buffer, 0, BufferSize) != -1) 
        { 
         fs.Write(Buffer, 0, BufferSize); 
        } 
       } 
      } 
     } 
     catch { } 

    } 
    private string[] GetFilesList(string FtpFolderPath, string UserName, string Password) 
    { 
     try 
     { 
      FtpWebRequest Request; 
      FtpWebResponse Response; 

      Request = (FtpWebRequest)FtpWebRequest.Create(new Uri(FtpFolderPath)); 
      Request.Credentials = new NetworkCredential(UserName, Password); 
      Request.Proxy = null; 
      Request.Method = WebRequestMethods.Ftp.ListDirectory; 
      Request.UseBinary = true; 

      Response = (FtpWebResponse)Request.GetResponse(); 
      StreamReader reader = new StreamReader(Response.GetResponseStream()); 
      string Data = reader.ReadToEnd(); 

      return Data.Split('\n'); 
     } 
     catch 
     { 
      return null; 
     } 
    } 


} 
0

Вы можете использовать скрипт Robo-FTP для отслеживания FTP-сайта для внесения изменений. Вот ссылка на образец сценария, который отправляет электронное письмо при каждом обнаружении изменения: http://kb.robo-ftp.com/script_library/show/40

Я рассмотрел предыдущий вопрос, который вы связали. Я думаю, вы должны иметь возможность модифицировать образец Robo-FTP и использовать команду SETLEFT с параметром/split, чтобы проанализировать имя папки и номер файла ISO измененного файла, а затем переместить файл в нужное место.

4

Вы не можете использовать FileSystemWatcher или любым другим способом, поскольку в протоколе FTP нет API для уведомления клиента об изменениях в удаленной директории.

Все, что вы можете сделать - это периодически перебирать удаленное дерево и находить изменения.

На самом деле это довольно просто реализовать, если вы используете FTP-клиентскую библиотеку, которая поддерживает рекурсивный список удаленного дерева. К сожалению, встроенный FTP-клиент .NET, FtpWebRequest нет. Но, например, с WinSCP .NET assembly версии 5.9 (или новее), вы можете использовать Session.EnumerateRemoteFiles method.

Смотрите статью Watching for changes in SFTP/FTP server:

// Setup session options 
SessionOptions sessionOptions = new SessionOptions 
{ 
    Protocol = Protocol.Ftp, 
    HostName = "example.com", 
    UserName = "user", 
    Password = "password", 
}; 

using (Session session = new Session()) 
{ 
    // Connect 
    session.Open(sessionOptions); 

    List<string> prevFiles = null; 

    while (true) 
    { 
     // Collect file list 
     List<string> files = 
      session.EnumerateRemoteFiles(
       "/remote/path", "*.*", EnumerationOptions.AllDirectories) 
      .Select(fileInfo => fileInfo.FullName) 
      .ToList(); 
     if (prevFiles == null) 
     { 
      // In the first round, just print number of files found 
      Console.WriteLine("Found {0} files", files.Count); 
     } 
     else 
     { 
      // Then look for differences against the previous list 
      IEnumerable<string> added = files.Except(prevFiles); 
      if (added.Any()) 
      { 
       Console.WriteLine("Added files:"); 
       foreach (string path in added) 
       { 
        Console.WriteLine(path); 
       } 
      } 

      IEnumerable<string> removed = prevFiles.Except(files); 
      if (removed.Any()) 
      { 
       Console.WriteLine("Removed files:"); 
       foreach (string path in removed) 
       { 
        Console.WriteLine(path); 
       } 
      } 
     } 

     prevFiles = files; 

     Console.WriteLine("Sleeping 10s..."); 
     Thread.Sleep(10000); 
    } 
} 

(я автор WinSCP)


Хотя, если вы на самом деле хотите, чтобы просто загрузить изменения, это способ проще , Просто используйте Session.SynchronizeDirectories в цикле.

session.SynchronizeDirectories(
    SynchronizationMode.Local, "/remote/path", @"C:\local\path", true).Check(); 

Если вы не хотите использовать 3rd библиотеку партии, вы должны делать с ограничениями FtpWebRequest. Например, как рекурсивно перечислить дерево удаленных каталогов с помощью FtpWebRequest, см. Мой ответ на C# Download all files and subdirectories through FTP.

Смежные вопросы