2010-02-09 31 views
10

我有一个filesystemwatcher,当文件被修改时会触发一个事件。一旦锁定被删除,我想从该文件读取。目前,我只是试图在事件被触发时打开文件,当正在复制大文件时,在事件发送之后文件锁保持一段时间,从而防止文件被打开以进行读取访问。FileSystemWatcher触发文件流打开

有什么建议吗?

回答

6

这实际上是一个doozie,除非问题空间已经显着改变,因为我最后不得不处理它。

最简单的方法是简单地尝试打开文件,捕获结果IOException,并且如果文件被锁定,请将其添加到队列中以便以后检查。您不能只尝试处理每个进入的文件,因为存在各种情况下会为同一个文件生成多个事件,因此在每个接收到的事件中设置一个重试循环可能会变成一场灾难。您需要将它们排队,然后定期检查队列。

这是一个基本的类模板,应该帮助你解决这个问题:

public class FileMonitor : IDisposable 
{ 
    private const int PollInterval = 5000; 

    private FileSystemWatcher watcher; 
    private HashSet<string> filesToProcess = new HashSet<string>(); 
    private Timer fileTimer; // System.Threading.Timer 

    public FileMonitor(string path) 
    { 
     if (path == null) 
      throw new ArgumentNullException("path"); 

     watcher = new FileSystemWatcher(); 
     watcher.Path = path; 
     watcher.NotifyFilter = NotifyFilters.FileName; 
     watcher.Created += new FileSystemEventHandler(FileCreated); 
     watcher.EnableRaisingEvents = true; 

     fileTimer = new Timer(new TimerCallback(ProcessFilesTimer), 
      null, PollInterval, Timeout.Infinite); 
    } 

    public void Dispose() 
    { 
     fileTimer.Dispose(); 
     watcher.Dispose(); 
    } 

    private void FileCreated(object source, FileSystemEventArgs e) 
    { 
     lock (filesToProcess) 
     { 
      filesToProcess.Add(e.FullPath); 
     } 
    } 

    private void ProcessFile(FileStream fs) 
    { 
     // Your code here... 
    } 

    private void ProcessFilesTimer(object state) 
    { 
     string[] currentFiles; 
     lock (filesToProcess) 
     { 
      currentFiles = filesToProcess.ToArray(); 
     } 
     foreach (string fileName in currentFiles) 
     { 
      TryProcessFile(fileName); 
     } 
     fileTimer.Change(PollInterval, Timeout.Infinite); 
    } 

    private void TryProcessFile(string fileName) 
    { 
     FileStream fs = null; 
     try 
     { 
      FileInfo fi = new FileInfo(fileName); 
      fs = fi.OpenRead(); 
     } 
     catch (IOException) 
     { 
      // Possibly log this error 
      return; 
     } 

     using (fs) 
     { 
      ProcessFile(fs); 
     } 

     lock (filesToProcess) 
     { 
      filesToProcess.Remove(fileName); 
     } 
    } 
} 

(注意 - 我从存储器中再调用这个这里,所以它可能不是完美的 - 让我知道,如果它是越野车。)

+0

不错,这就是我在等待的时候带的东西。我用了超时和重试等待,我希望有更优雅的东西,但是好吧;)(感谢一百万人的努力以获得最佳答复) – Matthew 2010-02-09 07:00:10