我有一个应用程序,我正在寻找一个文本文件,如果对文件做了任何更改,我使用OnChanged事件处理程序来处理事件。我正在使用NotifyFilters。LastWriteTime,但是事件仍然被触发两次。这是代码。
public void Initialize()
{
FileSystemWatcher _fileWatcher = new FileSystemWatcher();
_fileWatcher.Path = "C:\\Folder";
_fileWatcher.NotifyFilter = NotifyFilters.LastWrite;
_fileWatcher.Filter = "Version.txt";
_fileWatcher.Changed += new FileSystemEventHandler(OnChanged);
_fileWatcher.EnableRaisingEvents = true;
}
private void OnChanged(object source, FileSystemEventArgs e)
{
.......
}
在我的情况下,OnChanged被调用两次,当我改变文本文件version.txt并保存它。
我花了大量时间使用FileSystemWatcher,这里的一些方法将不起作用。我真的很喜欢禁用事件的方法,但不幸的是,它不工作,如果有>1文件被丢弃,第二个文件将错过大多数,如果不是所有的时间。
所以我使用以下方法:
private void EventCallback(object sender, FileSystemEventArgs e)
{
var fileName = e.FullPath;
if (!File.Exists(fileName))
{
// We've dealt with the file, this is just supressing further events.
return;
}
// File exists, so move it to a working directory.
File.Move(fileName, [working directory]);
// Kick-off whatever processing is required.
}
我知道这是一个老问题,但我遇到了同样的问题,上面的解决方案都没有真正解决我所面临的问题。我已经创建了一个字典,它将文件名与LastWriteTime映射。因此,如果文件不在字典中,将继续执行该进程,否则将检查最后一次修改时间是什么时候,如果与字典中的时间不同,则运行代码。
Dictionary<string, DateTime> dateTimeDictionary = new Dictionary<string, DateTime>();
private void OnChanged(object source, FileSystemEventArgs e)
{
if (!dateTimeDictionary.ContainsKey(e.FullPath) || (dateTimeDictionary.ContainsKey(e.FullPath) && System.IO.File.GetLastWriteTime(e.FullPath) != dateTimeDictionary[e.FullPath]))
{
dateTimeDictionary[e.FullPath] = System.IO.File.GetLastWriteTime(e.FullPath);
//your code here
}
}
解决方案实际上取决于用例。您是否在注意不更改的新文件,或每隔一段时间更改一次的文件或经常更改的文件?在我的情况下,它的变化不太频繁,我不想错过任何这些变化。
但是我也不想在写入过程尚未完成写入的地方发生更改事件。
在我的情况下,我注意到6 (6 !!)onchange事件写一个125字符的txt文件。
我的解决方案是民意调查和改变事件的混合,民意调查经常被消极地看待。正常轮询比较慢,比如每10秒一次,以防FileSystemWatcher (FSW)“错过”一个事件。轮询立即响应FSW更改事件。
关键是在FSW。更改事件时,轮询速度加快,例如每100毫秒,并等待直到文件稳定。因此我们有了“两阶段轮询”:阶段1比较慢,但在FSW文件更改事件时立即响应。第二阶段是快速的,等待一个稳定的文件。
如果FSW检测到多个文件更改,每个事件都会加速轮询循环,并有效地启动一个新的短等待周期。只有在轮询循环检测到上次写入时文件没有进一步的变化之后,它才假定文件是稳定的,并且您的代码可以处理更改后的文件。
我选择了10秒和100毫秒的超时,但是您的用例可能需要不同的超时值。
这里是轮询,其中AppConfig。fiIO是要注意的FileInfo:
private readonly EventWaitHandle ewhTimeout = new AutoResetEvent(false);
private void TwoPhasedPolling()
{
bool WaitForChange = true; //false: wait until stable
DateTime LastWriteTime = DateTime.MinValue;
while (true)
{
// wait for next poll (timeout), or FSW event
bool GotOne = ewhTimeout.WaitOne(WaitForChange ? 10 * 1000 : 100);
if (GotOne)
{
// WaitOne interrupted: end of Phase1: FSW detected file change
WaitForChange = false;
}
else
{
// WaitOne timed out: Phase2: check file write time for change
if (AppConfig.fiIO.LastWriteTime > LastWriteTime)
{
LastWriteTime = AppConfig.fiIO.LastWriteTime;
}
else
{
// End of Phase2: file has changed and is stable
WaitForChange = true;
// action on changed file
... your code here ...
}}}}
private void fileSystemWatcher1_Changed(object sender, FileSystemEventArgs e)
{
ewhTimeout.Set();
}
NB:是的,我也不喜欢}}}},但它使列表更短,这样你就不必滚动了:-)