2009-08-14 9 views
9

Comment puis-je implémenter un FileSystemWatcher pour un emplacement FTP (en C#). L'idée est chaque fois que quelque chose est ajouté dans l'emplacement FTP que je souhaite copier sur ma machine locale. Toutes les idées seront utiles.FileSystemWatcher pour FTP

Ceci est un suivi de ma question précédente Selective FTP download using .NET.

+0

Vous allez utiliser l'approche du type de sondage. Vous devez vérifier le site ftp périodiquement pour vérifier s'il y a un nouveau fichier. – jersoft

Répondre

14

Vous allez devoir implémenter une solution d'interrogation, où vous continuez à demander le contenu du répertoire régulièrement. Comparez cela à une liste en cache de l'appel précédent et déterminez ce qui s'est passé de cette façon.

Il n'y a rien dans le protocole FTP qui vous aidera malheureusement. Ecrivez un service simple pour créer FileSystemWatcher en pointant sur votre emplacement ftp.

3

Ensuite, lorsqu'un fichier est téléchargé ou modifié, un événement sera déclenché dans votre service, que vous pouvez ensuite utiliser pour copier le fichier sur votre machine locale.
File.Copy etc.

Hav un oeil à: this blog

+0

Est-ce que 'FileSystemWatcher' fonctionne avec des URL? –

+0

Emplacements UNC, pas les URL. – Bravax

7

Les travaux de classe FileSystemWatcher en vous inscrivant à des événements avec l'hôte système d'exploitation Windows. En tant que tel, il est limité à travailler sur les chemins locaux et les chemins UNC vers les répertoires hébergés sur les systèmes Windows. La documentation MSDN sur FileSystemWatcher explique les chemins que vous pouvez utiliser et certains des problèmes potentiels liés à l'utilisation de la classe.

Si vous souhaitez être informé des changements sur un site FTP, vous devrez utiliser un mécanisme d'interrogation pour demander l'état actuel des fichiers ou dossiers que vous souhaitez surveiller. Vous serez en mesure de voir quand les fichiers sont ajoutés et supprimés en comparant les instantanés du site FTP pour les changements et en soulevant des événements similaires lorsque vous détectez des changements. Malheureusement, vous ne serez pas en mesure de détecter les événements renommer, mais d'autres changements devraient être simples à surveiller de cette façon.

0

La façon dont je gère ceci est de télécharger un tableau d'octets à un élément, nommé ".ftpComplete". Le FileSystemWatcher surveille uniquement les fichiers ".ftpComplete" et supprime ceux-ci pour connaître le fichier téléchargé. Depuis le fichier « .ftpComplete » est à seulement 1 octet, il télécharge à peu près aussi vite qu'il est créé sur le serveur FTP, il peut donc être supprimé une fois que vous faites tout ce que vous devez le principal fichier uploadé

 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

vous pouvez surveiller l'emplacement FTP par la méthode suivante:

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

vous pouvez utiliser un script Robo-FTP pour surveiller le site FTP pour les changements. Voici un lien vers un exemple de script qui envoie un e-mail chaque fois qu'une modification est détectée: http://kb.robo-ftp.com/script_library/show/40

J'ai regardé la question précédente que vous avez liée. Je pense que vous devriez être capable de modifier l'exemple Robo-FTP et utiliser la commande SETLEFT avec l'option/split pour lui faire analyser le nom du dossier et le numéro de fichier ISO du fichier modifié, puis déplacez le fichier à l'emplacement approprié.

4

Vous ne pouvez pas utiliser le FileSystemWatcher ou tout autre moyen, car le protocole FTP ne dispose d'aucune API pour informer un client des modifications apportées au répertoire distant.

Tout ce que vous pouvez faire est d'itérer périodiquement l'arborescence distante et de trouver les changements.

En fait, il est plutôt facile à implémenter si vous utilisez une bibliothèque cliente FTP qui prend en charge la liste récursive d'une arborescence distante. Malheureusement, le client FTP intégré .NET, le FtpWebRequest ne fait pas. Mais par exemple avec WinSCP .NET assembly version 5.9 (ou plus récente), vous pouvez utiliser le Session.EnumerateRemoteFiles method.

Voir l'article 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); 
    } 
} 

(je suis l'auteur de WinSCP)


Bien que, si vous voulez vraiment il suffit de télécharger les changements, il est un moyen plus facile . Utilisez simplement le Session.SynchronizeDirectories dans la boucle.

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

Si vous ne souhaitez pas utiliser une bibliothèque 3ème partie, vous devez faire avec les limites de la FtpWebRequest. Pour obtenir un exemple de liste récursive d'une arborescence de répertoires distante avec le FtpWebRequest, voir ma réponse à C# Download all files and subdirectories through FTP.