FileSystemWatcher在队列中丢失文件

本文关键字:文件 队列 FileSystemWatcher | 更新日期: 2023-09-27 18:04:23

我编写了一个FileSystemWatcher,为每个文件调用一次pgm。但是我的一些文件丢了。我只用10-11个文件测试了代码。删除文件会被正确记录,但创建文件则不会。有些文件没有记录。在我的任务执行中是否有任何问题?或者Window Service有问题吗?

 public static FileSystemWatcher m_Watcher;
        static BlockingCollection<string> blockingCollection = new BlockingCollection<string>();
protected override void OnStart(string[] args)
    {
        current_directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        //XmlDocument xml = new XmlDocument();
        try
        {
            strDir = ConfigurationManager.AppSettings["Directory"];
            fileMask = ConfigurationManager.AppSettings["FileMask"];
            strBatfile = ConfigurationManager.AppSettings["Batch"];
            strlog = ConfigurationManager.AppSettings["Log"];
            m_Watcher = new FileSystemWatcher();

            m_Watcher.Filter = fileMask;
            m_Watcher.Path = strDir + "''";
            m_Watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
                             | NotifyFilters.FileName | NotifyFilters.DirectoryName;


            m_Watcher.Created += new FileSystemEventHandler(OnCreated);
            m_Watcher.Deleted += new FileSystemEventHandler(OnDeleated);
            m_Watcher.Renamed += new RenamedEventHandler(OnRenamed);

            m_Watcher.EnableRaisingEvents = true;
        }
        catch (Exception exception)
        {
            CustomException.Write(CustomException.CreateExceptionString(exception.ToString()));
        }
    }
    public static void OnDeleated(object source, FileSystemEventArgs e)
    {
        try
        {
            Log.getLogger("File deleated- Filename :" + e.Name + " at timestamp : " + DateTime.Now.ToString(), strlog);
        }
        catch (Exception exception)
        {
            CustomException.Write(CustomException.CreateExceptionString(exception, e.Name));
        }
    }
    private static void OnCreated(object source, FileSystemEventArgs e)
    {
        var exceptions = new ConcurrentQueue<Exception>();
        try
        {
            Task.Factory.StartNew(() =>
            {
                try
                {
                    blockingCollection.Add(e.Name.ToString());
                }
                catch (Exception)
                {
                    throw;
                }
            });
            Task.Factory.StartNew(() =>
            {
                try
                {

                    foreach (string value in blockingCollection.GetConsumingEnumerable())
                    {
                        System.Diagnostics.Process.Start(Service1.strBatfile);
                        Log.getLogger("File Processed after executing batch:  Filename ->:" + value + " " + "Batch File Executed- > " + Service1.strBatfile + " at timestamp : " + DateTime.Now.ToString(), Service1.strlog);
                    }
                }
                catch (Exception)
                {
                    throw;
                }

            });

        }
        catch (AggregateException ae)
        {
            foreach (var ex in ae.InnerExceptions)
            {
                CustomException.Write(CustomException.CreateExceptionString(ex, e.Name));
            }
        }
        finally
        {
            m_Watcher.EnableRaisingEvents = true;
        }
    }

FileSystemWatcher在队列中丢失文件

你正在使用许多线程/任务来清楚地理解代码是如何工作的。正如您所述,您希望一次只处理一个文件,您只需要一个线程/任务,该线程/任务在类(我假设是应用程序)的生命周期内存在。

如果我剥离你的代码,每次完成一个文件的处理,每当一个文件被放入某个文件夹时,这可能是一个实现。

注意我如何有一个ConcurrentQueue和一个方法读取队列。我还在流程实例上使用WaitForExit方法,以防止运行多个进程。

    static ConcurrentQueue<string> filenames = new ConcurrentQueue<string>();
    static void QueueHandler()
    {
        bool run = true;
        AppDomain.CurrentDomain.DomainUnload += (s, e) =>
        {
            run = false;
            filenames.Enqueue("stop");
        };
        while(run)
        {
            string filename;
            if (filenames.TryDequeue(out filename) && run)
            {
                var proc = new Process();
                proc.StartInfo.FileName = filename;
                proc.Start();
                proc.WaitForExit(); // this blocks until the process ends....
            }
        }
    }

现在我们需要一个单独的任务/线程来运行QueueHandlerFileSystemWatcher:

protected override void OnStart(string[] args)
{
        // have our queue reader method started
        Task.Factory.StartNew(QueueHandler);
        var fsw = new FileSystemWatcher();
        fsw.Created += (o, e) =>
            {
                // add a file to the queue
                filenames.Enqueue(e.FullPath);
                // optionally add polling for missed files
                // http://stackoverflow.com/questions/239988/filesystemwatcher-vs-polling-to-watch-for-file-changes
            };
        fsw.Path = ConfigurationManager.AppSettings["Directory"];
        fsw.NotifyFilter = NotifyFilters.FileName;
        fsw.Filter = ConfigurationManager.AppSettings["FileMask"];
        fsw.EnableRaisingEvents = true;
}

这个实现将在最坏的情况下使用三个线程:一个主线程,一个用于FileSystemWatcher的创建事件,一个用于QueueHandler,如果您的示例代码中每次在文件夹中创建新文件时都启动新的任务,FileSystemWatcher正在监视

OnCreated方法中启动两个任务,其中第二个任务似乎依赖于第一个任务的输出。但是,不能保证第一个任务在第二个任务执行时已经完成(甚至已经启动)。

您可以将这两个操作分组到一个任务中,然后依次执行,或者您可以将第一个任务的结果await

你的代码中也有很多信息丢失了。这显然不是"真正的"代码,因为OnDeleated[原文如此]拼写错误,无法编译。我们也无法看到您的外部进程是什么,或者您是如何试图将文件列表传递给它的。那里可能会有很多问题。是否有可能张贴实际代码?