2009-08-14 24 views
9

Làm cách nào để triển khai FileSystemWatcher cho vị trí FTP (trong C#). Ý tưởng là bất cứ khi nào bất cứ điều gì được thêm vào trong vị trí FTP tôi muốn sao chép nó vào máy địa phương của tôi. Bất kỳ ý tưởng nào đều hữu ích.FileSystemWatcher cho FTP

Đây là câu hỏi tiếp theo của câu hỏi trước của tôi Selective FTP download using .NET.

+0

Bạn sẽ sử dụng cách tiếp cận loại bỏ phiếu. Bạn phải kiểm tra trang web ftp định kỳ để kiểm tra xem có tệp mới hay không. – jersoft

Trả lời

14

Bạn sẽ phải triển khai giải pháp bỏ phiếu, nơi bạn tiếp tục yêu cầu nội dung thư mục theo định kỳ. So sánh điều này với danh sách được lưu trong bộ nhớ cache từ cuộc gọi trước đó và xác định điều gì đã xảy ra theo cách đó.

Không có gì trong giao thức FTP sẽ giúp bạn với điều này không may.

3

Viết một dịch vụ đơn giản để tạo FileSystemWatcher, trỏ vào vị trí ftp của bạn.

Sau đó, khi tệp được tải lên hoặc sửa đổi, sự kiện sẽ được kích hoạt trong dịch vụ của bạn, sau đó bạn có thể sử dụng sự kiện này để sao chép tệp vào máy cục bộ của mình.
File.Copy, vv

hav một cái nhìn tại địa chỉ: this blog

+0

Trình 'FileSystemWatcher' có hoạt động với URL không? –

+0

vị trí UNC, không phải của URL. – Bravax

7

Các FileSystemWatcher công trình lớp học bằng cách đăng ký cho các sự kiện với các máy chủ hệ điều hành Windows. Như vậy, nó được giới hạn để làm việc trên các đường dẫn cục bộ và các đường dẫn UNC tới các thư mục được lưu trữ trên các hệ thống Windows. Tài liệu MSDN trên FileSystemWatcher giải thích các đường dẫn mà bạn có thể sử dụng và một số vấn đề tiềm ẩn khi sử dụng lớp học.

Nếu bạn đang muốn được cảnh báo về những thay đổi trên trang FTP, bạn sẽ phải sử dụng cơ chế bỏ phiếu để yêu cầu trạng thái hiện tại của tệp hoặc thư mục mà bạn quan tâm theo dõi. Bạn sẽ có thể thấy khi nào các tệp được thêm và xóa bằng cách so sánh ảnh chụp nhanh của trang FTP cho các thay đổi và tăng các sự kiện tương tự khi bạn phát hiện các thay đổi. Thật không may bạn sẽ không thể phát hiện sự kiện đổi tên, nhưng những thay đổi khác nên được đơn giản để theo dõi theo cách này.

0

Cách tôi xử lý việc này là tải lên một mảng byte phần tử, có tên ".ftpComplete". FileSystemWatcher chỉ theo dõi các tệp ".ftpComplete" và xóa các tệp đó ở cuối để biết tệp thực được tải lên. Kể từ khi ".ftpComplete" tập tin là chỉ có 1 byte, nó upload về nhanh như nó được tạo ra trên máy chủ FTP, vì vậy nó có thể được xóa khi bạn làm bất cứ điều gì bạn cần phải có các tập tin được tải lên chính

 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

Bạn có thể theo dõi vị trí FTP bằng cách làm theo phương thức sau:

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

Bạn có thể sử dụng tập lệnh Robo-FTP để theo dõi trang FTP để thay đổi. Đây là liên kết đến tập lệnh mẫu gửi email bất cứ khi nào thay đổi được phát hiện: http://kb.robo-ftp.com/script_library/show/40

Tôi đã xem câu hỏi trước bạn đã liên kết. Tôi nghĩ bạn có thể sửa đổi mẫu Robo-FTP và sử dụng lệnh SETLEFT với tùy chọn/split để làm cho nó phân tích cú pháp tên thư mục và số tệp ISO của tệp đã thay đổi và sau đó di chuyển tệp đến vị trí thích hợp.

4

Bạn không thể sử dụng FileSystemWatcher hoặc bất kỳ cách nào khác, vì giao thức FTP không có bất kỳ API nào để thông báo cho khách hàng về các thay đổi trong thư mục từ xa.

Tất cả những gì bạn có thể làm là định kỳ lặp cây từ xa và tìm các thay đổi.

Thực sự khá dễ thực hiện, nếu bạn sử dụng thư viện máy khách FTP hỗ trợ danh sách đệ quy của cây từ xa. Thật không may, máy khách FTP tích hợp sẵn, FtpWebRequest thì không. Nhưng ví dụ với WinSCP .NET assembly phiên bản 5.9 (hoặc mới hơn), bạn có thể sử dụng Session.EnumerateRemoteFiles method.

Xem bài viết 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); 
    } 
} 

(Tôi là tác giả của WinSCP)


Mặc dù, nếu bạn thực sự muốn chỉ cần tải các thay đổi, đó là một cách dễ dàng hơn . Chỉ cần sử dụng Session.SynchronizeDirectories trong vòng lặp.

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

Nếu bạn không muốn sử dụng một thư viện của bên thứ 3, bạn phải làm với những hạn chế của FtpWebRequest. Ví dụ về cách đệ quy danh sách cây thư mục từ xa với số FtpWebRequest, hãy xem câu trả lời của tôi cho C# Download all files and subdirectories through FTP.

Các vấn đề liên quan