使用 FileSystemWatcher 和 C# 处理包含多个文件的文件夹

And*_*ndy 0 c# filesystemwatcher

我创建了一个相对简单的 Windows 应用程序,用于监视文件夹中的文件。在文件夹中创建新文件时,应用程序(通过 FileSystemWatcher)将打开文件并处理内容。长话短说,内容与 Selenium 一起使用,通过 IE11 自动化网页。此处理每个文件大约需要 20 秒。

问题是,如果在大致相同的时间或应用程序处理文件时在文件夹中创建了多个文件,则 FileSystemWatcher onCreated 看不到下一个文件。因此,当第一个文件的处理完成时,应用程序就会停止。同时,文件夹中有一个文件没有得到处理。如果在 onCreated 处理完成后添加文件,它可以正常工作并处理下一个文件。

有人可以指导我解决这个问题吗?非常欢迎过多的细节。

Geo*_*vos 5

FileSystemWatcher(正如您已经注意到的)不可靠,您将始终必须为丢失的文件添加“自定义”/手动逻辑(另外,请注意,您可能会看到同一文件的多个事件

您可以在下面看到一个简单的示例,其中包含对未处理文件的“背景”检查。
您可以通过使用并发集合来避免锁定,例如BlockingCollection
您也可以选择并行
处理文件我正在根据计时器处理文件,但您可以使用自己的策略。
如果您不想实时处理文件,可能您甚至不需要 FileSystemWatcher

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;

namespace ConsoleAppDemo
{
    class Program
    {
        private static object lockIbj = new object();
        private static List<string> _proccessedFiles = new List<string>();
        private static readonly List<string> toProccessFiles = new List<string>();
        private static List<string> _proccessingFiles = new List<string>();
        private const string directory = @"C:\Path";
        private const string extension = @"*.txt";
        static void Main(string[] args)
        {
            FileSystemWatcher f = new FileSystemWatcher();
            f.Path = directory;
            f.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
                             | NotifyFilters.FileName | NotifyFilters.DirectoryName;
            f.Filter = extension ;
            f.Created += F_Created;
            f.EnableRaisingEvents = true;

            Timer manualWatcher = new Timer(ManuallWatcherCallback, null, 0, 3000);

            Timer manualTaskRunner = new Timer(ManuallRunnerCallback, null, 0, 10000);

            Console.ReadLine();
        }

        private static void F_Created(object sender, FileSystemEventArgs e)
        {
            lock (lockIbj)
            {
                toProccessFiles.Add(e.FullPath);
                Console.WriteLine("Adding new File from watcher: " + e.FullPath);
            }

        }

        private static void ManuallWatcherCallback(Object o)
        {
            var files = Directory.GetFiles(directory, extension);
            lock (lockIbj)
            {
                foreach (var file in files)
                {
                    if (!_proccessedFiles.Contains(file) && !toProccessFiles.Contains(file) && !_proccessingFiles.Contains(file))
                    {
                        toProccessFiles.Add(file);
                        Console.WriteLine("Adding new File from manuall timer: " + file);
                    }
                }

            }
        }

        private static bool processing;
        private static void ManuallRunnerCallback(Object o)
        {
            if (processing)
                return;

            while (true)
            {
                //you could proccess file in parallel
                string fileToProcces = null;

                lock (lockIbj)
                {
                    fileToProcces = toProccessFiles.FirstOrDefault();
                    if (fileToProcces != null)
                    {
                        processing = true;
                        toProccessFiles.Remove(fileToProcces);
                        _proccessingFiles.Add(fileToProcces);
                    }
                    else
                    {
                        processing = false;
                        break;


                    }
                }

                if (fileToProcces == null)
                    return;

                //Must add error handling
                ProccessFile(fileToProcces);
            }
        }

        private static void ProccessFile(string fileToProcces)
        {
            Console.WriteLine("Processing:" + fileToProcces);
            lock (lockIbj)
            {
                _proccessingFiles.Remove(fileToProcces);
                _proccessedFiles.Add(fileToProcces);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)