FileSystemWatcher 在其队列中丢失文件 [英] FileSystemWatcher losing files in its queue

查看:40
本文介绍了FileSystemWatcher 在其队列中丢失文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我编写了一个 FileSystemWatcher 来为每个文件调用一次 pgm.但是我的一些文件丢失了.我只用 10-11 个文件测试了代码.正确记录文件的删除,但未正确记录创建.某些文件未记录.我的 TASK 实现中可能有什么问题吗?还是 Window Service 有问题?

I have written a FileSystemWatcher to call a pgm once for every file. But some of my files are lost. I tested the code with only 10-11 files. Deletion of a file is logged correctly, but not the creation. Some of the files are not logged. Is there maybe any problem in my TASK implementation? or is there any problem with 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;
        }
    }

推荐答案

您正在使用许多线程/任务的方式来清楚地了解代码的工作原理.正如您所说,您只想一次处理一个文件,您只需要一个在类的整个生命周期内都存在的线程/任务(我假设是应用程序).

You are using way to many threads/Tasks to get a clear understanding how the code works. As you stated that you want to only process one file at a time you need just one Thread/Task that lives for the lifetime of the class (and I assume the application).

如果我剥离您的代码以在文件被放入某个文件夹时一次处理一个文件,这可能是一种实现.

If I strip down your code to accomplish processing one file at a time whenever a file is dropped in a certain folder this could be one implementation.

注意我有一个 ConcurrentQueue 和一个读取该队列的方法.我也使用方法 WaitForExit 在流程实例上防止运行多个进程.

Notice how I have one ConcurrentQueue and ONE method that reads that queue. I also use the method WaitForExit on the process instance to prevent running more than one process.

    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....

            }
        }
    }

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

Now we need a single Task/Thread that will run QueueHandler and our FileSystemWatcher:

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 的 Created 事件,另一个用于 QueueHandler,如果您的示例代码是新的每次在 FileSystemWatcher 正在监视的文件夹中创建新文件时都会启动任务

This implementation will use at worst three threads: one main thread, one for the Created events of the FileSystemWatcher and one for the QueueHandler instead if your example code where new Tasks were started every time a new file was created in the folder the FileSystemWatcher was watching

这篇关于FileSystemWatcher 在其队列中丢失文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆