FileSystemWatcher 在其队列中丢失文件 [英] FileSystemWatcher losing files in its queue
问题描述
我编写了一个 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屋!