2009-08-14 23 views
9

如何为FTP位置(在C#中)实现FileSystemWatcher。这个想法是什么时候在FTP位置添加任何东西,我希望将它复制到我的本地机器。任何想法都会有所帮助。用于FTP的FileSystemWatcher

这是我以前的问题Selective FTP download using .NET的后续。

+0

您将使用轮询类型的方法。您必须定期检查ftp站点以检查是否有新文件。 – jersoft 2011-09-14 04:45:56

回答

14

你将不得不实施一个轮询解决方案,在这个解决方案中你需要定期询问目录内容。将它与先前调用的缓存列表进行比较,并确定发生了什么。

FTP协议中没有任何东西可以帮助你解决这个问题。

3

编写一个简单的服务来创建FileSystemWatcher,指向你的ftp位置。

然后当上传或修改文件时,会在您的服务中触发一个事件,然后您可以使用该事件将该文件复制到本地计算机。通过与主机Windows操作系统的事件注册this blog

+0

'FileSystemWatcher'是否适用于URL? – 2009-08-14 11:08:01

+0

UNC位置,而不是URL。 – Bravax 2009-08-14 11:13:46

7

FileSystemWatcher类作品:
File.Copy等

甲肝看看。因此,它仅限于在本地路径和UNC到Windows系统托管目录的路径上工作。关于FileSystemWatcher的MSDN文档解释了您可以使用的路径以及使用该类的一些潜在问题。

如果您希望在FTP站点发现更改提示,您将不得不使用轮询机制询问您有兴趣监视的文件或文件夹的当前状态。通过比较FTP站点的快照以进行更改并在检测到更改时发出类似事件,您将能够查看何时添加和删除文件。不幸的是,你无法检测到重命名事件,但其他更改应该很容易通过这种方式进行监视。

0

我处理这个的方式是上传一个名为“.ftpComplete”的元素字节数组。 FileSystemWatcher只能监视“.ftpComplete”文件,并将其从最后删除以了解上传的实际文件。由于“.ftpComplete”文件只有1个字节,它上传一样快,因为它是在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示例,并使用带有/ split选项的SETLEFT命令使其解析已更改文件的文件夹名称和ISO文件编号,然后将该文件移至适当的位置。

4

您不能使用FileSystemWatcher或任何其他方式,因为FTP协议没有任何API来通知客户端有关远程目录中的更改。

您所能做的就是定期迭代远程树并找到更改。

如果您使用支持远程树的递归列表的FTP客户端库,实现它实际上相当容易。不幸的是,内置的.NET FTP客户端,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(); 

如果你不想使用第三方库,你可以用FtpWebRequest的局限性要做。有关如何以FtpWebRequest递归列出远程目录树的示例,请参阅我对C# Download all files and subdirectories through FTP的回答。