1

我正在开发 ac# 程序,它使用 FilesystemWatcher 来监视添加到 monitor_directory 中的 PDF 文件。每次将文件添加到目录时,我将其添加到 BlockingQueue 中,该队列在另一个线程无限 while 循环中连续弹出,它在那里等待添加文件路径,之后我继续处理文件,最后一部分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 事件处理程序被触发两次,因此 BlockingQueue 有两次相同的条目,在这种情况下,在处理例程中,我验证文件是否尚未移动到输出目录(因为这是处理的最后部分包括将文件移动到那里),如果是这样我继续处理,如果不是我退出。2. 如果由于某种原因我在访问文件内容时收到错误消息:该文件正在被另一个进程使用,我从 Process 函数返回 FALSE 并将文件路径再次添加到队列中。

现在..这可行,但运行速度有点慢..考虑到我一直面临的两个问题,我该如何进行多线程处理.. 编辑: 如果我收到事件怎么办,将其添加到队列中,它被弹出,队列为空,然后我再次得到相同的事件,队列为空,所以它被添加,基本上我得到相同的事件处理两次?

4

2 回答 2

3

FileSystemWatcher 是出了名的健谈。

我想这就是我会做的...

  1. 在从 On_Create 调用中第二次添加之前,检查 BlockingQueue 是否已经有相关文件的条目。
  2. 您是否希望队列中有很多空路径?希望空检查只是一种预防措施。但是,如果您能提供帮助,请不要将空路径排入队列。
  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);
            }
        });

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

于 2013-06-19T16:03:26.550 回答
1

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

File.GetLastWriteTime(file);

或者您可以检查重复项。

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

ThreadPool.QueueUserWorkItem
于 2013-06-19T16:07:41.557 回答