我有一个应用程序,我正在寻找一个文本文件,如果对文件做了任何更改,我使用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并保存它。
代码可自定义禁用阻止第二个观察者升起的时间间隔,如果他们存在,则不阻止观察者:
namespace Watcher
{
class Static
{
public static DateTime lastDomain { get; set; }
public static string lastDomainStr { get; set; }
}
public partial class Form1 : Form
{
int minMs = 20;//time for blocking in ms
public Form1()
{
InitializeComponent();
Static.lastDomain = new DateTime(1970, 1, 1, 0, 0, 0);
Static.lastDomainStr = "";
Start();
}
private void Start()//Start watcher
{
//...
domain.Changed += new FileSystemEventHandler(Domain);
domain.EnableRaisingEvents = true;
//...you second unblocked watchers
second.Changed += new FileSystemEventHandler(Second);
second.EnableRaisingEvents = true;
}
private void Domain(object source, FileSystemEventArgs e)
{
if (now.Subtract(Static.lastDomain).TotalMilliseconds < minMs && Static.lastDomainStr == e.FullPath)return;
//...you code here
/* if you need form access
this.Invoke(new MethodInvoker(() =>{ textBox1.Text = "...";}));
*/
Static.lastDomain = DateTime.Now;
Static.lastDomainStr = e.FullPath;
}
private void Second(object source, FileSystemEventArgs e)
{
//...Second rised
}
}
}
主要原因是
第一个事件的最后一次访问时间是当前时间(文件写入或更改时间)。
第二个事件是文件最初的最后一次访问时间。
我在代码下解决。
var lastRead = DateTime.MinValue;
Watcher = new FileSystemWatcher(...)
{
NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite,
Filter = "*.dll",
IncludeSubdirectories = false,
};
Watcher.Changed += (senderObject, ea) =>
{
var now = DateTime.Now;
var lastWriteTime = File.GetLastWriteTime(ea.FullPath);
if (now == lastWriteTime)
{
return;
}
if (lastWriteTime != lastRead)
{
// do something...
lastRead = lastWriteTime;
}
};
Watcher.EnableRaisingEvents = true;
我可以通过添加一个函数来检查缓冲区数组中的重复项来做到这一点。
然后使用计时器在数组X时间内未被修改后执行该操作:
-每次有东西写入缓冲区时重置计时器
—对tick执行动作
这还捕获了另一种复制类型。如果修改文件夹内的文件,该文件夹也会引发Change事件。
Function is_duplicate(str1 As String) As Boolean
If lb_actions_list.Items.Count = 0 Then
Return False
Else
Dim compStr As String = lb_actions_list.Items(lb_actions_list.Items.Count - 1).ToString
compStr = compStr.Substring(compStr.IndexOf("-") + 1).Trim
If compStr <> str1 AndAlso compStr.parentDir <> str1 & "\" Then
Return False
Else
Return True
End If
End If
End Function
Public Module extentions
<Extension()>
Public Function parentDir(ByVal aString As String) As String
Return aString.Substring(0, CInt(InStrRev(aString, "\", aString.Length - 1)))
End Function
End Module
试试下面的代码:
class WatchPlotDirectory
{
bool let = false;
FileSystemWatcher watcher;
string path = "C:/Users/jamie/OneDrive/Pictures/Screenshots";
public WatchPlotDirectory()
{
watcher = new FileSystemWatcher();
watcher.Path = path;
watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite
| NotifyFilters.FileName | NotifyFilters.DirectoryName;
watcher.Filter = "*.*";
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Renamed += new RenamedEventHandler(OnRenamed);
watcher.EnableRaisingEvents = true;
}
void OnChanged(object sender, FileSystemEventArgs e)
{
if (let==false) {
string mgs = string.Format("File {0} | {1}",
e.FullPath, e.ChangeType);
Console.WriteLine("onchange: " + mgs);
let = true;
}
else
{
let = false;
}
}
void OnRenamed(object sender, RenamedEventArgs e)
{
string log = string.Format("{0} | Renamed from {1}",
e.FullPath, e.OldName);
Console.WriteLine("onrenamed: " + log);
}
public void setPath(string path)
{
this.path = path;
}
}