2012-02-21 78 views
1

我需要將文件的創建或複製/移動事件記錄到我將使用的文件夾中,我將使用FileSystemWatcher。問題是,當我在文件夾中粘貼一個文件時,FileSystemWatcher將引發一個創建事件。因此,如果我在該文件夾中共同粘貼10文件,則FileSystemWatcher會引發10個事件。我的要求是如果同時複製文件夾中的所有10個文件,則只會引發一個事件。一次引發FileSystemWatcher的多個事件

請建議。以下是我使用MSDN教程編寫的代碼。

公共類FileSystemWatcherUtil2 {

public static void Main() 
    { 
     Run(); 
    } 

    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] 
    public static void Run() 
    { 
     /* creation of a new FileSystemWatcher and set its properties */ 
     FileSystemWatcher watcher = new FileSystemWatcher(); 
     watcher.Path = @"C:\Users\TestFolder"; 

     /*watch for internal folder changes also*/ 
     watcher.IncludeSubdirectories = true; 

     /* Watch for changes in LastAccess and LastWrite times, and the renaming of files or directories. */ 
     watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; 

     /* event handlers */ 
     watcher.Changed += new FileSystemEventHandler(OnChanged); 
     watcher.Created += new FileSystemEventHandler(OnChanged); 
     watcher.Deleted += new FileSystemEventHandler(OnChanged); 
     watcher.Renamed += new RenamedEventHandler(OnRenamed); 

     /* watching started */ 
     watcher.EnableRaisingEvents = true; 

     /* user should quit the program to stop watching*/ 
     Console.WriteLine("Press \'q\' to quit the sample."); 
     while (Console.Read() != 'q') ; 
    } 

    /* event handlers definition for changed and renamed */ 
    private static void OnChanged(object source, FileSystemEventArgs e) 
    { 
     Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType); 
    } 

    private static void OnRenamed(object source, RenamedEventArgs e) 
    { 
     Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath); 
    } 

} 

回答

2

的想法是落實暴露自己CreatedEx事件,這將模擬FileSystemWatcher.Created事件,但會提高每10個Created事件OCCURENCES一個時間FileSystemWatcher的包裝。但請記住,我們無法確定所有處理程序Created事件是在單個複製/移動操作的範圍內引發的。爲了提高這種方法的可靠性,我建議設置一個DirectoryName NotifyFilters value,這樣你可以觀察到一個目錄,但是如果這符合你的要求。也許通過提供更多關於需求的細節,我們可以提供更多的細節,這樣方法會更可靠,基本上最重要的是確定大容量複製/移動操作的共同範圍,所以當yu複製100個文件和int時同時通過OS啓動的其他拷貝操作過程中,你需要從你感興趣前者操作過濾掉了。所以,文件或許有些共同標準等

  1. FileSystemWatcher實現包裝
  2. 暴露自己CreatedEx事件
  3. 認購FileSystemWatcher.Created事件並在處理程序啓動斯塔定時器持續200毫秒。如果FileSystemWatcher.Created事件沒有發生 - 提出自己的CreatedEx事件,否則重置計時器並等待200ms週期。

定時器的時間段您可以用實驗的方式確定,只需複製多個不同大小的文件並查看哪個超時就足夠了。

如果您需要提高CreatedEx事件一次整整10個併發事件出現次數 - 您可以在FileSystemWatcher.Created事件處理程序介紹簡單的計數器和遞減,而當counter==0 - 提高自己的CreatedEx事件。

+1

我認爲唯一的真正答案OP的是,你不能,10個文件創建10個事件。這是一個FileSystemWatcher的,而不是一個PasteWatcher;) – Lazarus 2012-02-21 11:13:19

+0

@Lazarus:您可以使用包裝這將提高每10個內部'Created'事件OCCURENCES – sll 2012-02-21 11:27:15

+0

沒有自己的'CreatedEx'有一次,還是依靠10個內部'Created'事件存在的在彼此的超時期限內(在你的例子中是200ms)?您是否確實能夠確定這10個事件是單個粘貼活動的結果,而不是批處理文件複製文件的結果? – Lazarus 2012-02-21 11:35:30

1

FileSystemWatcher無法知道複製是否作爲一個操作完成,因爲不存在一次複製多個文件等問題。 Windows資源管理器使得看起來像通過使用拖放,但它本質上是多個副本。

如果您希望可以在FileSystemWatcher上編寫一個簡單的包裝器,它可以接受所有創建事件,並且如果它們發生,相隔200毫秒,則會引發「多次創建」事件。

這裏是監控創建事件的工作代碼。如果您需要和/或公開其他屬性,您可以將包裝器基於此來監視其他事件。

public class MyWatcher 
{ 
    private FileSystemWatcher watcher = new FileSystemWatcher(); 
    private System.Timers.Timer timer; 
    private object listSync = new object(); 
    private List<FileSystemEventArgs> events = new List<FileSystemEventArgs>(); 

    public delegate void FileSystemMultipleEventHandler(object sender, FileSystemEventArgs[] events); 
    public FileSystemMultipleEventHandler OnMultipleFilesCreated { get; set; } 

    public MyWatcher(string path, NotifyFilters notifyFilters, string filter) 
    { 
     this.watcher.Path = path; 
     this.watcher.Created += FileCreated; 
     watcher.Filter = filter; 
     watcher.EnableRaisingEvents = true; 
    } 

    private void FileCreated(object sender, FileSystemEventArgs e) 
    { 
     if (this.timer != null) 
     { 
      this.timer.Stop(); 
      lock (this.listSync) this.events.Add(e); 
      this.timer.Start(); 
     } 
     else 
     { 
      lock (this.listSync) this.events.Add(e); 
      this.timer = new Timer(200); 
      this.timer.Elapsed += MultipleFilesCreated; 
      this.timer.Start(); 
     } 
    } 

    private void MultipleFilesCreated(object stat, ElapsedEventArgs args) 
    { 
     if (OnMultipleFilesCreated != null) 
     { 
      FileSystemEventArgs[] result; 
      lock (this.listSync) 
      { 
       // make a copy 
       result = events.ToArray(); 
       this.events = new List<FileSystemEventArgs>(); 
      } 
      OnMultipleFilesCreated(this, result); 
     } 
     this.timer.Stop(); 
    } 
} 

我使用鎖在這裏進行訪問的事件列表是線程安全的(定時器VS FileCreated事件)。不使用任何併發收集,因爲他們沒有ClearAll(),我需要鎖定和刪除項目一個接一個,還是要重新收集與鎖。

+0

感謝馬切伊,去嘗試你的方法,我也在想同樣的。 – user1223082 2012-02-22 08:16:32

+0

如果一切正常,記得將其標記爲:-) – 2012-02-22 09:19:59

+0

當文件之一,是非常大的,並得到複製需要更多的時間比我們的默認時間(比如200毫秒)這種做法是失敗的答案 – user1223082 2012-02-23 12:47:37