程序设计问题,filesystemwatcher,多线程c#

时间:2013-06-19 15:39:57

标签: c# multithreading filesystemwatcher

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

调度线程:

    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);
            }
        }
    }

Process函数测试文件是否存在,进行一些处理并将PDF文件移动到输出目录。

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

现在......这有效,但它的工作有点慢..我怎么能通过考虑我面临的两个问题来做这个多线程.. 修改 如果我得到事件,将它添加到队列,它被弹出,队列为空,然后我再次得到相同的事件,队列是空的,所以它被添加了,基本上我得到同样的事件处理TWICE怎么办? / p>

2 个答案:

答案 0 :(得分:3)

FileSystemWatcher非常讨厌。

我认为这就是我要做的......

  1. 在On_Create调用中再次添加第二次之前,检查BlockingQueue是否已有相关文件的条目。
  2. 您希望队列中有很多空路径吗?希望空检查只是一个预防措施。但是如果你能帮助它,不要将空路径排队。
  3. 在您的工作线程中,只需出列并处理
  4. 如果您的工作线程处理错误,您可以再次将其排队,或者您可能希望将其置于一个例外情况,因为如果您获得足够的不可处理文件,他们可能会占用您的队列并减慢您的速度。
  5. 执行此多线程的一种简单方法是每次出列路径时都启动一个新任务...

        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);
                }
            });
    

    对于生产代码,您还需要将取消令牌传递给任务,并具有停止循环和任务的机制。

答案 1 :(得分:0)

1) FileSystemWatcher 会两次通知您,因为文件分两步更新:首先是数据,然后是元数据。因此,您可以使用以下内容检查最新的写入是否已被考虑在内:

File.GetLastWriteTime(file);

或者您可以检查重复项。

2)你没有使用多线程:你一次处理一个文件,所以你可以产生一些线程来执行Process方法,例如:使用方法:

ThreadPool.QueueUserWorkItem