2009-08-14 5 views
9

Come è possibile implementare un FileSystemWatcher per un percorso FTP (in C#). L'idea è quando qualcosa viene aggiunto nella posizione FTP che voglio copiare sul mio computer locale. Qualsiasi idea sarà utile.FileSystemWatcher per FTP

Questo è un seguito della mia precedente domanda Selective FTP download using .NET.

+0

Si utilizzerà l'approccio del tipo di polling. Devi controllare periodicamente il sito ftp per verificare se c'è un nuovo file. – jersoft

risposta

14

È necessario implementare una soluzione di polling, in cui si continua a chiedere periodicamente il contenuto della directory. Confronta questo con un elenco memorizzato nella cache dalla chiamata precedente e determina cosa è successo in quel modo.

Non c'è nulla nel protocollo FTP che ti possa aiutare, purtroppo.

3

Scrivere un servizio semplice per creare FileSystemWatcher, indicando la propria posizione ftp.

Quindi, quando un file viene caricato o modificato, nel servizio verrà generato un evento che è possibile utilizzare per copiare il file sul computer locale.
File.Copy ecc

Hav un'occhiata a: this blog

+0

'FileSystemWatcher' funziona con gli URL? –

+0

Posizioni UNC, non URL. – Bravax

7

I FileSystemWatcher opere classe registrandosi per eventi con il sistema operativo Windows host. Pertanto, è limitato a lavorare su percorsi locali e percorsi UNC a directory ospitate su sistemi Windows. La documentazione MSDN su FileSystemWatcher spiega i percorsi che è possibile utilizzare e alcuni dei potenziali problemi con l'utilizzo della classe.

Se si desidera essere avvisati delle modifiche su un sito FTP, sarà necessario utilizzare un meccanismo di polling per chiedere lo stato corrente dei file o delle cartelle che si desidera monitorare. Sarai in grado di vedere quando i file vengono aggiunti e rimossi confrontando le istantanee del sito FTP per le modifiche e sollevando eventi simili quando rilevi le modifiche. Sfortunatamente non sarai in grado di rilevare gli eventi di rinomina, ma altre modifiche dovrebbero essere semplici da monitorare in questo modo.

0

Il modo in cui gestisco questo è di caricare un array di byte a un elemento, denominato ".ftpComplete". FileSystemWatcher controlla solo i file ".ftpComplete" e ne estrae la parte per conoscere il file effettivamente caricato. Dal momento che il file ".ftpComplete" è solo 1 byte, si carica circa veloce quanto è creato sul server FTP, in modo che possa essere eliminato una volta che fate tutto ciò che è necessario con il file caricato principale

 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

È possibile monitorare la posizione FTP dal seguente metodo:

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

è possibile utilizzare uno script Robo-FTP per monitorare il sito FTP per le modifiche. Ecco un collegamento a uno script di esempio che invia un'email ogni volta che viene rilevata una modifica: http://kb.robo-ftp.com/script_library/show/40

Ho esaminato la domanda precedente che hai collegato. Penso che dovresti essere in grado di modificare l'esempio Robo-FTP e utilizzare il comando SETLEFT con l'opzione/split per farlo analizzare il nome della cartella e il numero di file ISO del file modificato e quindi spostare il file nella posizione corretta.

4

Non è possibile utilizzare FileSystemWatcher o altro modo, perché il protocollo FTP non ha alcuna API per notificare a un client le modifiche nella directory remota.

Tutto quello che puoi fare è iterare periodicamente l'albero remoto e trovare le modifiche.

In realtà è piuttosto semplice da implementare, se si utilizza una libreria client FTP che supporta l'elenco ricorsivo di un albero remoto. Sfortunatamente, il client FTP .NET incorporato, lo FtpWebRequest non lo fa. Ad esempio, con WinSCP .NET assembly versione 5.9 (o più recente), è possibile utilizzare Session.EnumerateRemoteFiles method.

vedere l'articolo 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); 
    } 
} 

(io sono l'autore di WinSCP)


Anche se, se si vuole realmente scaricare solo le modifiche, si tratta di un modo più semplice . Basta usare lo Session.SynchronizeDirectories nel loop.

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

Se non si desidera utilizzare una libreria di terze parti, si hanno a che fare con le limitazioni del FtpWebRequest. Per un esempio come elencare in modo ricorsivo un albero di directory remoto con FtpWebRequest, vedere la risposta a C# Download all files and subdirectories through FTP.