2009-08-14 101 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的回答。