2013-06-19 104 views
0

我正在开发一个c#程序,它使用FilesystemWatcher监视添加到monitor_directory中的PDF文件。每次将文件添加到目录时,我都会将其添加到在另一个线程无限循环中不断弹出的BlockingQueue,然后等待文件路径添加,然后继续处理文件,最后一部分PDF文件处理将其移至输出目录。程序设计问题,filesystemwatcher,多线程c#

的调度线程:

如果该文件存在
private static void ThreadProc(object param) 
    { 

     FileMonitorManager _this = (FileMonitorManager)param; 
     FileProcessingManager processingManager = new FileProcessingManager(); 
     processingManager.RegisterProcessor(new ExcelFileProcessor()); 
     processingManager.RegisterProcessor(new PdfFileProcessor()); 

     while (true) 
     { 
      try 
      { 
       var path = (string)_this.FileQueue.Dequeue(); 
       if (path == null) 
        break; 
       bool b = processingManager.Process(path); 
       if (!b) 
       { 
        _this.FileQueue.Enqueue(path); 
        Console.WriteLine("\n\nError on file: " + path); 
       } 
       else 
        Console.WriteLine("\n\nSucces on file: " + path); 

      } 
      catch (System.Exception e) 
      { 
       Console.WriteLine(e.Message); 
      } 
     } 
    } 

处理功能的测试中,进行一些处理,并移动PDF文件到输出目录。

我遇到了两个问题: 1.来自FileSystemWatcher的On_Create事件处理程序被触发TWICE,因此BlockingQueue具有相同的条目两次,在这种情况下,在处理例程中验证文件是否未被移动到输出目录(因为这是处理的最后部分包括在那里移动文件),如果是的话,我继续处理,如果没有我退出。 2.如果由于某种原因,我得到一个错误访问该文件的内容说:该文件正在被另一个进程使用我从Process函数返回FALSE并再次将文件路径添加到队列中。

现在..这工作,但它的工作原理有点慢。我如何能做到这一点的多线程通过采取考虑2个问题我一直面临着.. 编辑: 如果我得到的事件,将其添加到队列中,弹出,队列为空,然后再次获得相同的事件,队列为空,因此它被添加,基本上我得到了处理TWICE的相同事件?

回答

0

1)FileSystemWatcher的通知您两次。因此,您可以使用类似的方式检查最近的写入是否已被考虑到:

File.GetLastWriteTime(file); 

或者您可以检查重复项。 2)你没有使用多线程:你一次处理一个文件,所以你可以产生一些线程来执行Process方法,例如:使用:

ThreadPool.QueueUserWorkItem 
+0

已编辑结账 – AlexandruC

+0

您可以保留一张地图,将每个文件与最后编辑的时间相关联。然后,如果您看到使用GetLastWriteTime获取的上次修改时间与处理文件时相同,则无需执行任何操作,您可以忽略。如果您认为发生了变化,您甚至可以取消当前处理并使用当前文件重新启动它。 – Pragmateek

+0

非常有趣,这个策略是否可以将相同的文件再次添加到监视器目录中?如果我把这个文件放在整个地方,writeTime是否保持不变?我什么时候清理地图?并且在什么情况下,我会收到每个文件只有一个通知?因为我目前只有一个,我不知道它发生了什么 – AlexandruC

2

FileSystemWatcher是臭名昭着的。看到

我觉得这是我会做什么?

  1. 检查是否BlockingQueue的已经从On_Create通话将它第二次之前有问题的文件中的条目。
  2. 你期望在队列中有很多空路径吗?希望空检查只是一种预防措施。但是,如果你能帮助它,不要Enqueue null路径。
  3. 在您的工作线程刚刚出列和处理
  4. 如果你的工作线程得到一个错误处理它,你可以重新入队,或者你可能要预留它作为一个特例,因为如果你得到足够的无法处理的文件,他们可以豕你的队列,并减慢你的速度。

一个简单的方法来做到这一点的多线程是刚开始每次出队路径时新任务......

Task.Factory.StartNew(() => 
     { 
      try 
      { 
       var path = (string) _this.FileQueue.Dequeue(); 
       if (path == null) 
        break; 
       bool b = processingManager.Process(path); 
       if (!b) 
       { 
        _this.FileQueue.Enqueue(path); 
        Console.WriteLine("\n\nError on file: " + path); 
       } 
       else 
        Console.WriteLine("\n\nSucces on file: " + path); 

      } 
      catch (System.Exception e) 
      { 
       Console.WriteLine(e.Message); 
      } 
     }); 

对于生产代码,您还需要通过一个取消标记成该任务,并有一个机制来停止循环和任务。首先数据,则:因为文件分两步更新

+0

我故意排队时,我想要无限循环停止。另一个问题是,多线程处理这些IO操作是否会使程序更快? – AlexandruC

+1

假设processingManager.Process执行CPU密集型工作,那么几乎可以肯定是的。这假定你是CPU绑定的...如果你是I/O绑定然后没有。 – Kevin

+0

对于任务API +1,仍旧习惯于旧的ThreadPool;) – Pragmateek